/* BLACKGLASS game screen. The story is the main column; the side panel holds the map, pack and
   journal and can be hidden. Phones get one view at a time with a bottom tab bar.
   Map styles live in map.css. Reading settings set --story-font, --story-size and --story-leading. */

:root {
  --story-font: var(--font-serif);
  --story-size: 19px;
  --story-leading: 1.62;
}

body.game { overflow: hidden; height: 100vh; height: 100dvh; padding: 0; }

/* Safe areas (notched phones, mostly when installed as an app): the shell keeps the top bar, the
   story, the side panel and the travel veil clear of the notch and rounded corners. At the foot,
   the phone tab bar pads itself (so its background runs under the home indicator); wider screens
   pad the shell instead. */
.game-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  height: 100vh; height: 100dvh;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* ---- top bar ------------------------------------------------------------------------------ */
.game-bar {
  display: flex; align-items: center; gap: 0.6rem; min-width: 0;
  padding: 0.4rem 0.9rem; border-bottom: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.08em; color: var(--muted);
  background: var(--bg); min-height: 2.9rem;
}
.game-bar .wordmark { font-size: 0.75rem; text-decoration: none; }
.game-bar .fragment-name { text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--faint); }
.game-bar .spacer { flex: 1; }
.icon-btn {
  background: none; border: 1px solid transparent; color: var(--muted); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: 0.9rem; min-width: 2.3rem; height: 2.3rem; cursor: pointer;
}
.icon-btn:hover { border-color: var(--line-strong); color: var(--text-strong); }
/* Music on/off (game-view.js showMusic): lit when on; dimmed and struck through when off. Opens
   the volume popover below (.music-pop) — it does not itself toggle the setting any more. */
.music-btn { position: relative; font-size: 1.05rem; font-family: var(--font-sans); }
.music-btn[aria-pressed="true"] { color: var(--accent); }
.music-btn[aria-pressed="false"] { color: var(--faint); }
.music-btn[aria-pressed="false"]::after {
  content: ''; position: absolute; left: 30%; right: 30%; top: 50%; height: 1.5px;
  background: currentColor; transform: rotate(-45deg); pointer-events: none;
}
/* The level indicator: a hairline under the note that fills with the current volume (width set
   from game-view.js showMusic(), via the CSSOM — inline style="" attributes are blocked by CSP). */
.music-level {
  position: absolute; left: 22%; right: 22%; bottom: 5px; height: 2px; border-radius: 1px;
  background: var(--line-strong); overflow: hidden; pointer-events: none;
}
.music-level > span { display: block; height: 100%; width: 0; background: currentColor; }

/* ---- music volume popover ------------------------------------------------------------------- */
/* position: fixed (not absolute), positioned from the ♪ button's rect in game-view.js
   positionMusicPopover() — the same pattern as the map's Key/Places popovers (map.css). */
.music-pop {
  position: fixed; z-index: 50; width: min(17rem, calc(100vw - 1.5rem));
  background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--radius);
  padding: 0.7rem 0.9rem; box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5);
  font-family: var(--font-sans); text-transform: none; letter-spacing: normal;
}
.music-pop[hidden] { display: none; }
.music-pop-now { margin: 0 0 0.5rem; font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.06em; color: var(--accent); }
.music-pop-now[hidden] { display: none; }
.music-pop-label {
  display: block; margin-bottom: 0.4rem; font-family: var(--font-mono); font-size: 0.6875rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
}
.music-pop-row { display: flex; align-items: center; gap: 0.7rem; }
/* A generous track and thumb: an easy target from 360px phones up. */
.music-pop-row input[type="range"] {
  flex: 1; accent-color: var(--accent); height: 2rem; cursor: pointer; touch-action: none;
}
.music-pop-out { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--text); min-width: 2.6em; text-align: right; }
.music-pop-hint { margin: 0.5rem 0 0; font-size: 0.75rem; color: var(--faint); }
.save-status { white-space: nowrap; display: inline-flex; align-items: center; gap: 0.4rem; }
.save-status .short { display: none; }
.save-status::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.save-status[data-state="idle"]::before { display: none; }
.save-status[data-state="saved"]::before { background: var(--ok); }
.save-status[data-state="saving"]::before { background: var(--warn); animation: pulse 1s infinite alternate; }
.save-status[data-state="error"]::before, .save-status[data-state="conflict"]::before, .save-status[data-state="stale"]::before { background: var(--danger); }
.save-status[data-state="local"]::before { background: var(--accent); }
.save-status[data-state="error"], .save-status[data-state="conflict"], .save-status[data-state="stale"] { color: var(--danger); }
@keyframes pulse { from { opacity: 0.3; } to { opacity: 1; } }

/* ---- main layout --------------------------------------------------------------------------- */
/* The side panel takes a share of the width (--side-frac, set by game-view.js once the player drags
   the divider; 1/3 by default, so the story has 2/3), never narrower than 18rem nor leaving the
   story less than 22.5rem. Declared here, not on :root, so 100% and --side-frac resolve against the
   game area (the travel expansion below uses the same value). */
.game-main {
  --side-width: clamp(18rem, calc((100% - 6px) * var(--side-frac, 0.33333)), calc(100% - 6px - 22.5rem));
  display: grid; min-height: 0;
  grid-template-columns: minmax(0, 1fr) 6px var(--side-width);
}
.game-main[data-panel="closed"] { grid-template-columns: minmax(0, 1fr) 2.6rem; }
.game-main[data-panel="closed"] .pane-splitter { display: none; }
.pane-splitter {
  cursor: col-resize; background: var(--line); position: relative; touch-action: none; z-index: 5;
  transition: background 0.15s;
}
.pane-splitter::after { content: ''; position: absolute; inset: 0 -5px; }
.pane-splitter:hover, .pane-splitter.dragging, .pane-splitter:focus-visible { background: var(--accent); outline: none; }
body.resizing { cursor: col-resize; user-select: none; }
body.resizing canvas, body.resizing .pane { pointer-events: none; }
.game-main[data-panel="closed"] .pane-side { display: none; }
.panel-rail { display: none; }
.game-main[data-panel="closed"] .panel-rail {
  display: flex; flex-direction: column; border-left: 1px solid var(--line); background: var(--bg-raised);
}
.panel-rail button {
  writing-mode: vertical-rl; background: none; border: 0; border-bottom: 1px solid var(--line); color: var(--muted); cursor: pointer;
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.2em; text-transform: uppercase; padding: 1rem 0;
}
.panel-rail button:hover { color: var(--text-strong); background: var(--panel); }

.pane { min-height: 0; min-width: 0; overflow: hidden; display: flex; flex-direction: column; position: relative; }
.pane-side { background: var(--bg-raised); }

/* ---- story ------------------------------------------------------------------------------------ */
.story-head {
  display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
  padding: 0.55rem clamp(1rem, 4vw, 3rem); border-bottom: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--muted);
}
.story-head .here-name { color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.story-head .here-time { white-space: nowrap; color: var(--faint); }

.story-scroll {
  position: relative; flex: 1; overflow-y: auto; overscroll-behavior: contain;
  padding: 0 clamp(1rem, 5vw, 4rem);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 2.2rem, #000 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 2.2rem, #000 100%);
}
.story-inner { max-width: var(--gui-story-width, 42em); margin: 0 auto; font-family: var(--story-font); font-size: var(--story-size); line-height: var(--story-leading); }
.story-tail { height: 45vh; }

.log p { margin: 0 0 0.95em; }
.passage { padding-top: 1.6rem; transition: opacity 0.6s ease; }
/* Once a new passage begins, the earlier ones decay slowly until they are hardly there. Scrolling
   back up to them (game-view.js adds .reading-back) brings them back quickly. */
[data-dim-past="1"] .passage.past { opacity: 0.1; transition: opacity 5s ease-in; }
[data-dim-past="1"] .story-scroll.reading-back .passage.past { opacity: 1; transition: opacity 0.4s ease-out; }
[data-dim-past="1"] .passage.past:hover { opacity: 0.8; transition: opacity 0.4s ease-out; }
.passage .entry { animation: rise 0.35s ease-out both; }
.passage.past .entry, .passage .entry.pending { animation: none; }
.entry.pending { display: none; }
/* Reading a paragraph at a time (game-view.js paceSegments()): what is still held back is not shown
   (nor read by screen readers) until it is reached; each later paragraph rises in as it comes. The
   animation is cut by reduced motion (base.css) and ?anim=0 (html.no-anim). */
.passage .held, .passage p.pending { display: none; }
/* A passage's picture anchored at a later paragraph (placeart-view.js anchorPassageArt) is not shown
   before that paragraph: while it is held back or not yet typed. */
.passage figure.passage-art.pa-wait, .passage figure.passage-art:has(+ p.held), .passage figure.passage-art:has(+ p.pending),
.passage figure.passage-art:has(+ figure.passage-art + p.held), .passage figure.passage-art:has(+ figure.passage-art + p.pending) { display: none; }
.passage p.paced { animation: rise 0.45s ease-out both; }
.passage.past p.paced, .passage p.paced.pending { animation: none; }
.story-continue {
  display: inline-flex; align-items: center; gap: 0.5rem; margin: 0.1rem 0 0; padding: 0.45rem 0.8rem 0.45rem 0.1rem;
  background: none; border: 0; border-radius: var(--radius); color: var(--faint); cursor: pointer;
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase;
}
.story-continue:hover { color: var(--accent); }
.story-continue:focus-visible { color: var(--accent); outline: 1px solid var(--line-strong); outline-offset: 2px; }
.story-continue[hidden] { display: none; }
.story-continue-mark { font-size: 0.95rem; letter-spacing: 0; animation: nudge 2.4s ease-in-out infinite; }
@keyframes nudge { 0%, 100% { transform: translateY(0); opacity: 0.7; } 50% { transform: translateY(2px); opacity: 1; } }
@keyframes rise { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

.caret { display: inline-block; width: 0.5em; height: 1em; margin-left: 1px; vertical-align: -0.12em; background: var(--accent); opacity: 0.7; animation: blink 1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

.log-place {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 400; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--muted); margin: 0.6rem 0 1rem; display: flex; align-items: center; gap: 0.75rem;
}
.log-place::after { content: ''; flex: 1; height: 1px; background: var(--line); }
/* Place art (js/ui/placeart-view.js, docs/PLACEART.md): the picture of a place under its name, drawn
   at a whole number of device pixels per picture pixel (sized by the script), hidden by the setting. */
.place-art { margin: -0.2rem 0 1.2rem; display: flex; justify-content: center; }
.place-art img { display: block; max-width: 100%; height: auto; image-rendering: crisp-edges; image-rendering: pixelated; }
[data-place-art="0"] .place-art { display: none; }
/* An epic vista (BG-140): its wide framing may be wider than the text column, centred over it, up to the
   story panel's width (the script sizes it); its phone framing, in a portrait window, is as wide as the
   column, above the words. */
.place-art.epic[data-frame="wide"] img { max-width: none; }
/* An animated picture (BG-143, js/ui/placeart-player.js): a canvas laid exactly over the picture plays its moving
   parts; the image stays under it for its alt text. */
.place-art { position: relative; }
.place-art-motion { position: absolute; display: block; image-rendering: crisp-edges; image-rendering: pixelated; pointer-events: none; }
.place-art.pa-moving > img { opacity: 0; }
.log-you { font-family: var(--font-mono); font-size: 0.78em; color: var(--faint); margin: 0 0 0.9rem !important; letter-spacing: 0.02em; }
.log-you::before { content: '› '; color: var(--accent); }
.log-verse { font-style: italic; padding-left: 1.4em; border-left: 1px solid var(--line-strong); color: var(--text-strong); }
.log-insight { margin: 1.3em 0; padding: 0.15em 0 0.15em 1em; border-left: 2px solid var(--accent); color: var(--text-strong); }
.log-insight p { margin: 0 !important; font-style: italic; }
.kicker { display: block; font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.3rem; font-style: normal; }
.log-reinterpret { font-family: var(--font-mono); font-size: 0.8em; margin: 0.8em 0 !important; color: var(--accent-strong); }
.log-reinterpret s { color: var(--faint); text-decoration-thickness: 1px; }
.log-reinterpret .arrow { color: var(--faint); margin: 0 0.5rem; }
.log-memory { font-family: var(--font-mono); font-size: 0.78em; color: var(--warn); }
.log-memory::before { content: '✦ '; }
.log-time { font-style: italic; color: var(--muted); }
.log-notice { font-family: var(--font-mono); font-size: 0.78em; color: var(--muted); border: 1px dashed var(--line-strong); padding: 0.6rem 0.8rem; }

.glass-screen {
  margin: 1.4em 0; padding: 1.4rem 1rem; background: #030404; border: 1px solid #1b2320;
  font-family: var(--font-mono); font-size: clamp(0.8rem, 2.2vw, 1.05rem); letter-spacing: 0.12em;
  color: #1c2622; text-align: center; line-height: 1.9; white-space: pre; overflow: hidden;
}
.glass-screen.live { animation: glass-wake 3.4s steps(1, end) both; }
/* A fully fed glass (the room of glass) comes up and stays lit: "sharp and steady, every mark whole". */
.glass-screen.steady { color: #cfeee0; text-shadow: 0 0 6px rgba(160, 255, 210, 0.45), 0 0 18px rgba(120, 220, 180, 0.2); }
.glass-screen.steady.live { animation: glass-wake-steady 1.6s steps(1, end) both; }
@keyframes glass-wake-steady { 0% { opacity: 0; } 6% { opacity: 1; } 9% { opacity: 0.4; } 14% { opacity: 1; } 100% { opacity: 1; } }
@keyframes glass-wake {
  0% { opacity: 0; } 4% { opacity: 1; color: #cfeee0; text-shadow: 0 0 6px rgba(160, 255, 210, 0.55), 0 0 18px rgba(120, 220, 180, 0.25); }
  6% { opacity: 0.2; } 9% { opacity: 1; } 40% { opacity: 0.85; } 42% { opacity: 1; }
  70% { opacity: 1; color: #cfeee0; } 78% { opacity: 0.6; } 84% { opacity: 0.25; } 92% { opacity: 0.08; }
  100% { opacity: 1; color: #1c2622; text-shadow: none; }
}

.skip-hint {
  position: absolute; right: 1rem; bottom: 0.8rem; background: var(--panel); border: 1px solid var(--line); color: var(--faint);
  font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.08em; padding: 0.35rem 0.6rem; border-radius: var(--radius); cursor: pointer;
}
.skip-hint[hidden] { display: none; }

/* ---- choices ------------------------------------------------------------------------------------ */
.choices { margin-top: 1.4rem; padding-top: 1rem; border-top: 1px solid var(--line); transition: opacity 0.4s ease; }
.choices:empty { display: none; }
.choices.waiting { visibility: hidden; opacity: 0; }
.choice-group + .choice-group { margin-top: 0.9rem; }
.choice-group h3 { margin: 0 0 0.3rem; font-size: 0.625rem; letter-spacing: 0.22em; color: var(--faint); }
.choice {
  display: flex; width: 100%; text-align: left; gap: 0.8rem; align-items: baseline;
  background: none; border: 0; border-left: 2px solid transparent; color: var(--text);
  font: inherit; font-size: 0.94em; line-height: 1.4; padding: 0.45rem 0.7rem; cursor: pointer; border-radius: 0 var(--radius) var(--radius) 0;
}
.choice:hover:not(:disabled), .choice:focus-visible { background: var(--panel); border-left-color: var(--accent); color: var(--text-strong); outline: none; }
.choice .key { font-family: var(--font-mono); font-size: 0.72rem; color: var(--faint); min-width: 1rem; }
.choice .choice-label { flex: 1; }
.choice .meta { font-family: var(--font-mono); font-size: 0.72rem; color: var(--faint); white-space: nowrap; padding-left: 0.75rem; }
.choice-go .choice-label { color: var(--muted); }
.choice-go:hover .choice-label { color: var(--text-strong); }
.choice:disabled { color: var(--faint); cursor: not-allowed; }
.choice .why { display: block; font-size: 0.85em; color: var(--faint); font-style: italic; }
/* The way forward in a scene of waiting (content `onward: true`): a quiet verdigris edge and key. */
.choice.is-onward { border-left-color: rgba(159, 183, 170, 0.45); }
.choice.is-onward .key { color: var(--accent); }
.choice.is-onward .choice-label { color: var(--text-strong); }

/* ---- side panel ---------------------------------------------------------------------------------- */
.side-tabs { display: flex; border-bottom: 1px solid var(--line); }
.side-tabs button {
  flex: 1; background: none; border: 0; border-bottom: 2px solid transparent; color: var(--muted);
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
  padding: 0.75rem 0.5rem; cursor: pointer;
}
.side-tabs button[aria-selected="true"] { color: var(--text-strong); border-bottom-color: var(--accent); }
.side-tabs .panel-toggle { flex: 0 0 2.6rem; font-size: 1rem; letter-spacing: 0; border-left: 1px solid var(--line); }
.side-tabs button[data-tab] { min-width: 0; overflow: hidden; text-overflow: clip; white-space: nowrap; }
.side-tabs button:hover, .side-tabs button:focus-visible { color: var(--text-strong); outline: none; }
.side-tabs button:focus-visible { box-shadow: inset 0 0 0 1px var(--accent); }
.side-tabs .side-tool { flex: 0 0 2.2rem; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-left: 1px solid var(--line); }
.side-tabs .side-tool[hidden] { display: none; }
.side-tabs .side-tool[aria-pressed="true"] { color: var(--accent); }
.side-tool svg, .slot-btn svg { fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.side-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.side-page { display: none; padding: 1rem; overflow: auto; flex: 1; min-height: 0; font-size: calc(var(--story-size) * 0.84); }
.side-page.active { display: flex; flex-direction: column; }
.side-page[data-page="journal"].active, .side-page[data-page="pack"].active { display: block; }
.side-page h2 { margin: 1.4rem 0 0.6rem; font-size: 0.72rem; letter-spacing: 0.18em; color: var(--muted); }
.side-page h2:first-child { margin-top: 0; }

/* ---- the stacked side panel (wide screens only) ---------------------------------------------------
   Two views at once, map over pack by default, each under a slim header with Collapse and Expand,
   split by a draggable divider (game-view.js applyLayout(): data-slot on the pages, data-collapsed
   and data-expanded on the panel, --stack-rows for the grid). The pages never move in the DOM; the
   grid places them. Phones keep one view at a time, so none of this applies below 62rem. */
.slot-head, .slot-splitter { display: none; }
@media (min-width: 62.01rem) {
  .pane-side[data-layout="stack"] .side-body {
    display: grid; grid-template-columns: minmax(0, 1fr); align-content: start;
    grid-template-rows: var(--stack-rows, auto minmax(0, 1fr) 6px auto minmax(0, 1fr));
  }
  .pane-side[data-layout="stack"] .slot-head {
    display: flex; align-items: center; gap: 0.15rem; min-width: 0;
    padding: 0 0.35rem 0 1rem; height: 1.9rem; border-bottom: 1px solid var(--line); background: var(--bg-raised);
    font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--muted);
  }
  .pane-side[data-layout="stack"] [data-slot-head="a"] { grid-row: 1; }
  .pane-side[data-layout="stack"] [data-slot-head="b"] { grid-row: 4; }
  /* Map or Recollections chosen (BG-157): one view fills the panel, without a header (the tab names it). */
  .pane-side[data-layout="stack"][data-solo] .slot-head { display: none; }
  .slot-head .slot-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; }
  .slot-btn {
    flex: 0 0 auto; width: 1.6rem; height: 1.6rem; padding: 0; display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: 2px; color: var(--faint); cursor: pointer;
  }
  .slot-btn:hover, .slot-btn:focus-visible { color: var(--text-strong); background: var(--panel); outline: none; }
  .slot-btn[aria-pressed="true"] { color: var(--accent); }
  .slot-collapse svg { transition: transform 0.15s; }
  .slot-collapse[aria-expanded="false"] svg { transform: rotate(-90deg); }
  .pane-side[data-layout="stack"] .slot-splitter {
    display: block; grid-row: 3; cursor: row-resize; background: var(--line); position: relative; touch-action: none; z-index: 5;
    transition: background 0.15s;
  }
  .slot-splitter::after { content: ''; position: absolute; inset: -5px 0; }
  .slot-splitter:hover, .slot-splitter.dragging, .slot-splitter:focus-visible { background: var(--accent); outline: none; }
  .pane-side[data-layout="stack"] .side-page { display: none; padding: 0.75rem 1rem; }
  .pane-side[data-layout="stack"] .side-page[data-slot="a"] { display: block; grid-row: 2; }
  .pane-side[data-layout="stack"] .side-page[data-slot="b"] { display: block; grid-row: 5; }
  .pane-side[data-layout="stack"] .side-page[data-page="map"][data-slot] { display: flex; flex-direction: column; }
  /* The map fits whatever height its slot has (it asks for most of the screen on its own). */
  .pane-side[data-layout="stack"] .map-view { min-height: 0; }
  .pane-side[data-layout="stack"] .map-frame { min-height: 5rem; }
  .pane-side[data-layout="stack"][data-collapsed~="a"] .side-page[data-slot="a"],
  .pane-side[data-layout="stack"][data-collapsed~="b"] .side-page[data-slot="b"],
  .pane-side[data-layout="stack"][data-collapsed~="a"] .slot-splitter,
  .pane-side[data-layout="stack"][data-collapsed~="b"] .slot-splitter,
  .pane-side[data-layout="stack"][data-expanded="a"] [data-slot-head="b"],
  .pane-side[data-layout="stack"][data-expanded="a"] .side-page[data-slot="b"],
  .pane-side[data-layout="stack"][data-expanded="b"] [data-slot-head="a"],
  .pane-side[data-layout="stack"][data-expanded="b"] .side-page[data-slot="a"],
  .pane-side[data-layout="stack"][data-expanded="a"] .slot-splitter,
  .pane-side[data-layout="stack"][data-expanded="b"] .slot-splitter { display: none; }
  body.resizing-rows { cursor: row-resize; user-select: none; }
  body.resizing-rows canvas, body.resizing-rows .pane-story, body.resizing-rows .side-page { pointer-events: none; }
}

/* ---- journal ------------------------------------------------------------------------------------ */
.journal-tools { position: sticky; top: -1rem; background: var(--bg-raised); padding: 0 0 0.8rem; margin: 0 0 0.4rem; z-index: 2; }
.journal-search { font-size: 0.9rem !important; }
.entries { list-style: none; padding: 0; margin: 0; }
.entries li { padding: 0.55rem 0; border-bottom: 1px solid var(--line); }
.entries .title { font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.06em; color: var(--text-strong); }
.entries .former { font-family: var(--font-mono); font-size: 0.72rem; color: var(--faint); }
.entries .former s { margin-right: 0.4rem; }
.entries p { margin: 0.25rem 0 0; }
.entries .standing { color: var(--accent); font-style: italic; }
.entries mark { background: rgba(199, 154, 91, 0.3); color: var(--text-strong); border-radius: 2px; }

/* Topics and entries collapsed until opened (BG-153): each is a button (keyboard, aria-expanded) with a
   small chevron; an open topic shows its entries, an open entry its words. */
.jsec { border-bottom: 1px solid var(--line); }
.side-page .jsec h2 { margin: 0; }
.jsec-toggle, .jentry-toggle {
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit; background: none; border: 0;
  margin: 0; width: 100%; display: flex; align-items: center; gap: 0.1rem; text-align: left; cursor: pointer; border-radius: 2px;
}
.jsec-toggle { padding: 0.75rem 0; }
.jentry-toggle { padding: 0; }
.jsec-toggle::before, .jentry-toggle::after {
  content: ''; flex: none; width: 0.38rem; height: 0.38rem; border: solid currentColor; border-width: 0 1.5px 1.5px 0;
  transform: rotate(-45deg); opacity: 0.7; transition: transform 160ms ease;
}
.jsec-toggle::before { margin-right: 0.6rem; }
.jentry-toggle::after { margin-left: auto; color: var(--faint); }
.jsec-toggle[aria-expanded="true"]::before, .jentry-toggle[aria-expanded="true"]::after { transform: rotate(45deg); }
.jsec-toggle:hover, .jentry-toggle:hover .title { color: var(--text-strong); }
.jsec-toggle:focus-visible, .jentry-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.jsec > .entries { padding: 0 0 0.6rem 0.98rem; }
.jsec > .entries > li:last-child { border-bottom: 0; }
.jentry-toggle .title { flex: 1 1 auto; min-width: 0; }
.jentry-body[hidden] { display: none; }
.jentry-map { margin-top: 0.35rem; }
.jentry-where { color: var(--faint); font-style: italic; font-size: 0.9em; }

/* New journal entries: a small glowing dot until they have been seen. It sits on the Recollections
   (journal) buttons (tab, rail, phone tab), on each section with something new and on each new entry.
   Once the entry is on screen, .is-fading shrinks and fades the dot over 600 ms (DOT_FADE_MS in
   journal-view.js), then the class goes. Reduced motion: no pulse and a plain fade. ?anim=0
   (html.no-anim) cuts both. Warm amber-gold (Jake, 2026-10-01, BG-145): it reads on the dark panels
   and is not the red of a warning. */
:root { --new-dot: #e8b65a; --new-dot-glow: rgba(232, 182, 90, 0.75); }
.new-dot,
.has-new::after,
.entries li.is-new::before {
  content: ''; display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--new-dot); box-shadow: 0 0 0.45rem 0.05rem var(--new-dot-glow);
  animation: new-dot-pulse 2.8s ease-in-out infinite;
  transition: opacity 600ms ease, transform 600ms ease;
}
.new-dot { margin-left: 0.55em; vertical-align: 0.1em; }
.has-new::after { margin-left: 0.45em; vertical-align: 0.15em; }
.entries li.is-new { position: relative; }
.entries li.is-new::before { position: absolute; left: -0.8rem; top: 0.95em; }
.is-fading > .new-dot, h2.is-fading .new-dot, .has-new.is-fading::after, .entries li.is-fading::before {
  opacity: 0; transform: scale(0.2); animation: none;
}
@keyframes new-dot-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0.3rem 0 var(--new-dot-glow); }
  50% { opacity: 0.6; box-shadow: 0 0 0.6rem 0.1rem var(--new-dot-glow); }
}
@media (max-width: 420px) {
  .mobile-tabs button { letter-spacing: 0.06em; padding-inline: 0.15rem; }
}
@media (prefers-reduced-motion: reduce) {
  .new-dot, .has-new::after, .entries li.is-new::before { animation: none; transition: opacity 600ms ease; }
  .is-fading > .new-dot, h2.is-fading .new-dot, .has-new.is-fading::after, .entries li.is-fading::before { transform: none; }
}
.note-form { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.4rem; }
.note-form textarea, .note-edit textarea { min-height: 3.4rem; font-family: var(--story-font); font-size: 0.95em; }
.notes .note-text { white-space: pre-wrap; }
.note-meta { gap: 0.3rem; margin-top: 0.3rem; }
.row .spacer, .note-meta .spacer { flex: 1; }
.empty { color: var(--faint); font-style: italic; }

/* ---- pack ---------------------------------------------------------------------------------------- */
/* Two columns when there is room and something for the second (Jake, 2026-09-28; BG-157, 2026-10-02):
   the inventory grid (and the weight bar above it) on the left, the lists (on your back, on the ground,
   a pack animal's load) on the right, once the pack pane itself - not the window - is at least 36rem
   wide and pack-view.js has marked .pack-cols.has-lists. A container query on the pane's own scroll
   container means it reflows live as the side panel's dividers move. With nothing to list, one column,
   so the grid has the whole width: on a wide panel layoutGrid() then scales the cells up with it (Jake:
   "on a full-screen browser ... the inventory looks tiny"). With lists, the grid's column takes two
   shares to the lists' one, never below 20rem, the lists never below 12rem so a long name still reads.
   DOM order never changes (How you are, then the grid, then the lists), only the CSS. */
.side-page[data-page="pack"] { container-type: inline-size; container-name: pack-pane; }
.pack-cols { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 1.75rem; align-items: start; }
.pack-col-main, .pack-col-lists { min-width: 0; }
@container pack-pane (min-width: 36rem) {
  .pack-cols.has-lists { grid-template-columns: minmax(20rem, 2fr) minmax(12rem, 1fr); }
}
.pack-head { margin-bottom: 0.9rem; }
.pack-weight-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 0.35rem; font-size: 0.85rem; }
.meter { position: relative; height: 6px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 3px; }
.meter-fill { position: absolute; inset: 0 auto 0 0; background: var(--accent); border-radius: 3px; transition: width 0.4s ease; }
.is-heavy .meter-fill { background: var(--warn); }
.meter-mark { position: absolute; top: -3px; bottom: -3px; width: 1px; background: var(--warn); opacity: 0.8; }
.hint.warn { color: var(--warn); margin: 0.4rem 0 0; }

.pack-grid {
  position: relative; display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); grid-template-rows: repeat(var(--rows), auto);
  gap: 3px; padding: 3px; background: #07090a; border: 1px solid var(--line-strong); border-radius: var(--radius);
  touch-action: none; user-select: none; outline: none;
}
.pack-grid:focus-visible { border-color: var(--accent); }
/* Once pack-view.js layoutGrid() has fixed the column width (a whole number of device pixels per sprite
   pixel), the grid shrinks to its columns and sits centred. */
.pack-grid.is-laid { width: max-content; max-width: 100%; margin-inline: auto; }
.pack-cell { aspect-ratio: 1; background: var(--panel); border: 1px solid var(--line); border-radius: 2px; }
.pack-cell.drop-target { background: rgba(159, 183, 170, 0.18); border-color: var(--accent); }
.pack-item {
  position: relative; z-index: 1; margin: 0; min-width: 0; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.15rem;
  background: linear-gradient(160deg, #22292b, #181d1f); border: 1px solid #3c4649; border-radius: 3px;
  color: var(--text-strong); cursor: grab; padding: 1px; font: inherit;
}
.pack-item:hover { border-color: var(--accent); }
.pack-item.is-selected { border-color: var(--accent-strong); box-shadow: 0 0 0 1px var(--accent-strong), 0 0 12px rgba(159, 183, 170, 0.25); }
.pack-item.dragging { z-index: 5; cursor: grabbing; opacity: 0.85; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.6); }
.pack-item.perishable { background: linear-gradient(160deg, #2b2720, #1d1a16); border-color: #4a4234; }
/* Pixel-art item icons (public/js/ui/sprites.js): a shared base look plus an 'icon-fill' variant
   that fills its container (the pack-grid cell footprint) instead of using its own width/height).
   Grid items carry no caption text (name/weight stay in title/aria-label, and in the detail panel
   below when selected) so a rotated footprint's icon (pre-rotated by sprites.js from it.rot) has
   the whole cell, with only the button's 1px padding round it. pack-view.js layoutGrid() then gives
   every icon in the grid the same whole number of device pixels per sprite pixel (sprites.js
   snapIcons()); the 100% size below only holds until it has run. */
.item-icon {
  image-rendering: pixelated; -ms-interpolation-mode: nearest-neighbor; display: inline-block; vertical-align: middle; flex: 0 0 auto;
  /* Decorative only (alt="", aria-hidden, draggable="false" already set): never starts a native
     image drag or eats the pointer gesture the pack grid's own drag-to-rearrange relies on. */
  -webkit-user-drag: none; user-select: none; -webkit-user-select: none; pointer-events: none;
}
.item-icon.icon-fill { width: 100%; height: 100%; object-fit: contain; }
.pack-icon { flex: 1 1 0; min-height: 0; width: 100%; display: flex; align-items: center; justify-content: center; }
/* The detail of the thing chosen, as a modal over the Belongings pane (Jake, 2026-10-01): a backdrop over
   the whole pane and the card held in view while the pane scrolls, so choosing a thing never resizes the
   grids. ×, Esc or a click on the backdrop closes it (pack-view.js closeDetail()). */
[data-page="pack"] { position: relative; }
.pack-modal { position: absolute; inset: 0; z-index: 20; background: rgba(4, 6, 7, 0.55); display: flex; justify-content: center; align-items: flex-start; padding: 0 1rem; }
.pack-modal[hidden] { display: none; }
.pack-modal > .pack-card {
  position: sticky; top: 12vh; margin-top: 12vh; width: min(26rem, 100%); max-height: 70vh; overflow: auto;
  padding: 0.9rem 1rem 0.8rem; background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
}
.pack-card .pack-modal-close { float: right; margin: -0.35rem -0.4rem 0 0.5rem; background: none; border: 0; color: var(--muted); font-size: 1.25rem; line-height: 1; cursor: pointer; padding: 0.2rem 0.35rem; }
.pack-card .pack-modal-close:hover, .pack-card .pack-modal-close:focus-visible { color: var(--text-strong); }
.pack-detail .row { flex-wrap: wrap; gap: 0.4rem; }
.pack-detail .title { font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-strong); letter-spacing: 0.06em; }
.pack-detail p { margin: 0.25rem 0 0.5rem; }
.pack-counters { list-style: none; padding: 0; margin: 0; }
.pack-counters li { display: flex; align-items: center; gap: 0.6rem; padding: 0.4rem 0; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.pack-counters .count { color: var(--accent-strong); min-width: 2rem; }
.pack-counters .cname { flex: 1; min-width: 8rem; }
/* A pack animal's load (pack-view.js animalHTML): a name opens its description, as selecting a pack item does. */
.pack-animal { margin-top: 1.2rem; }
.pack-load .linklike { background: none; border: 0; padding: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 0.2em; }
.pack-load .load-desc { flex-basis: 100%; margin: 0.2rem 0 0; color: var(--muted); }
/* How the Belongings tab works (Jake, 2026-10-01): a small ? beside the Pockets heading opens it as a
   popover (the HTML popover attribute: Esc or a click outside closes it), instead of a paragraph under
   the lists that crowded the layout. */
.pack-help-btn {
  flex: none; width: 1.15rem; height: 1.15rem; margin-block: -0.3rem; padding: 0; border-radius: 50%; border: 1px solid var(--line-strong);
  background: none; color: var(--muted); font: 600 0.7rem/1 var(--font-sans); cursor: pointer;
}
.pack-help-btn:hover, .pack-help-btn:focus-visible { color: var(--text-strong); border-color: var(--accent); }
.pack-help-pop {
  max-width: min(22rem, calc(100vw - 2rem)); margin: auto; padding: 0.8rem 1rem; border: 1px solid var(--line-strong);
  border-radius: var(--radius); background: var(--panel); color: var(--text); font-size: 0.875rem; line-height: 1.45;
}
.pack-help-pop p { margin: 0 0 0.5rem; }
.pack-help-pop p:last-child { margin-bottom: 0; }
.pack-help-pop::backdrop { background: rgba(0, 0, 0, 0.35); }

/* The Belongings pane never scrolls (BG-162, Jake 2026-10-02: "I do not want any scrolling in the inventory so
   all contents must always fit inside that pane"). The pane's content is one column (.pack-fit) as tall as the
   pane: "How you are" at its natural height, then the grid and the lists, which take the rest. pack-view.js
   layoutGrid() sizes the cells so the grids fit what is left across and down; the lists (on your back, on the
   ground, a pack animal) scroll in their own area when they are longer than the room left for them: under the
   grids in one column, or beside them in two. In a short pane layoutGrid() makes room in steps (.pack-compact:
   without "How you are" and the weight's small print, which the story's header also shows; .pack-tight:
   without the weight; .pack-tiny: without the tabs), then squeezes the cells (.is-squeezed). A pane as tall as
   its content (no height of its own) is unchanged: .pack-fit's 100% is then its content. */
.side-page[data-page="pack"] { overflow: hidden; }
.pack-fit { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.pack-fit > .pack-state { flex: none; }
.pack-fit > .pack-cols { flex: 1 1 auto; min-height: 0; grid-template-rows: auto minmax(0, 1fr); }
.pack-fit .pack-col-main { align-self: start; }
.pack-fit .pack-col-lists { align-self: stretch; min-height: 0; overflow: auto; overscroll-behavior: contain; }
@container pack-pane (min-width: 36rem) {
  .pack-fit > .pack-cols.has-lists { grid-template-rows: minmax(0, 1fr); }
}
.pack-compact .pack-state, .pack-compact .pack-weight-split, .pack-compact .pack-head .hint { display: none; }
.pack-tight .pack-head { display: none; }
.pack-tiny .pack-tabs-row { display: none; }
/* Cells squeezed below a sprite's size: the icons shrink to their cells (no whole-pixel snap). */
.is-squeezed .item-icon.icon-fill { width: 100%; height: 100%; }
/* The hover card (BG-162, Jake 2026-10-02: "a hover on the inventory items that looks just like the interaction
   modal"): the menu's card - its panel, edge, shadow and words - without the buttons, beside the thing under the
   mouse or the keyboard's focus, kept inside the pane by pack-view.js placeHover(). It never takes the pointer. */
.pack-hovercard {
  position: absolute; z-index: 15; width: max-content; max-width: 18rem; overflow: hidden; pointer-events: none;
  padding: 0.7rem 0.85rem 0.55rem; background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55);
}
.pack-hovercard[hidden] { display: none; }
.pack-hovercard .pack-detail > :last-child { margin-bottom: 0; }

/* Satchel and pockets (BG-145, Jake 2026-10-01; each under its own tab since BG-157, 2026-10-02): the
   pockets are a 2 x 5 grid laid 5 across, with the satchel's cell size (pack-view.js layoutGrid()), one
   kind of thing per cell with its count on the sprite. The cell's tint is the thing's
   state (engine.pocketsView()): red when some has gone bad, amber going off, a fainter amber with a day
   or two left, a cool grey for a part-burnt candle or torch; a dashed amber edge for more than the
   pockets now hold (an older save). The same state is in each cell's label and in its menu. */
.pack-weight-split { margin: 0.3rem 0 0; font-size: 0.72rem; letter-spacing: 0.02em; }
.pack-grids { display: flex; justify-content: center; align-items: flex-start; min-width: 0; }
.pack-satchel, .pack-pockets { min-width: 0; }
.pack-satchel[hidden], .pack-pockets[hidden] { display: none; }
/* Satchel | Pockets: two small tabs over the grid, the ? beside them; a warm dot on a tab while
   something in it is new (BG-157). */
.pack-tabs-row { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.6rem; border-bottom: 1px solid var(--line); }
.pack-tabs { display: flex; gap: 0.2rem; }
.pack-tab {
  font: inherit; font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted); background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  padding: 0.45rem 0.55rem 0.4rem; cursor: pointer; white-space: nowrap;
}
.pack-tab[aria-selected="true"] { color: var(--text-strong); border-bottom-color: var(--accent); }
.pack-tab:hover, .pack-tab:focus-visible { color: var(--text-strong); outline: none; }
.pack-tab:focus-visible { box-shadow: inset 0 0 0 1px var(--accent); }
/* A thing new to the player: a warm dot in its cell's corner until it is touched (BG-157), or rested on with
   the mouse or the keyboard (BG-162). */
.pack-item.is-new::after, .pocket-item.is-new::after {
  content: ''; position: absolute; top: 3px; right: 3px; z-index: 2; width: 0.45rem; height: 0.45rem; border-radius: 50%;
  background: var(--gui-pack-dot, var(--new-dot)); box-shadow: 0 0 0.4rem 0.05rem var(--gui-pack-dot-glow, var(--new-dot-glow)); pointer-events: none;
}
/* Every unread dot of the belongings pulses slowly (BG-162, Jake 2026-10-02: "all yellow inventory dots should
   pulse slowly now"): on a thing's cell, on the Satchel and Pockets tabs, and on the Belongings tab, rail and
   phone tab. A slow ease in and out of the dot's brightness and glow, deeper than the Recollections' pulse so
   it is seen; Admin -> GUI settings' animation speed sets its pace (js/shell/gui-motion.js) and reduced motion
   (the system's, or the owner's for everyone) holds it steady. */
@keyframes pack-dot-pulse {
  0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 0.5rem 0.1rem var(--gui-pack-dot-glow, var(--new-dot-glow)); }
  50% { opacity: 0.35; transform: scale(0.78); box-shadow: 0 0 0.15rem 0 var(--gui-pack-dot-glow, var(--new-dot-glow)); }
}
.pack-item.is-new::after, .pocket-item.is-new::after, .pack-tab.has-new::after,
[data-tab="pack"].has-new::after, [data-rail="pack"].has-new::after, .mobile-tabs [data-view="pack"].has-new::after {
  animation: pack-dot-pulse 2.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .pack-item.is-new::after, .pocket-item.is-new::after, .pack-tab.has-new::after,
  [data-tab="pack"].has-new::after, [data-rail="pack"].has-new::after, .mobile-tabs [data-view="pack"].has-new::after { animation: none; }
}
html.gui-reduce-motion .pack-item.is-new::after, html.gui-reduce-motion .pocket-item.is-new::after, html.gui-reduce-motion .pack-tab.has-new::after,
html.gui-reduce-motion [data-tab="pack"].has-new::after, html.gui-reduce-motion [data-rail="pack"].has-new::after,
html.gui-reduce-motion .mobile-tabs [data-view="pack"].has-new::after { animation: none; }
.pockets-grid {
  display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); grid-auto-rows: auto;
  gap: 3px; padding: 3px; background: #07090a; border: 1px solid var(--line-strong); border-radius: var(--radius);
  user-select: none;
}
.pockets-grid.is-laid { width: max-content; max-width: 100%; }
.pocket-cell { aspect-ratio: 1; background: var(--panel); border: 1px solid var(--line); border-radius: 2px; }
.pocket-cell.is-overflow { border-style: dashed; }
.pocket-item {
  position: relative; aspect-ratio: 1; margin: 0; min-width: 0; min-height: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, #22292b, #181d1f); border: 1px solid #3c4649; border-radius: 3px;
  color: var(--text-strong); cursor: pointer; padding: 1px; font: inherit;
}
.pocket-item:hover { border-color: var(--accent); }
.pocket-item:focus-visible { outline: 1px solid var(--accent-strong); outline-offset: 1px; }
.pocket-item.is-selected { border-color: var(--accent-strong); box-shadow: 0 0 0 1px var(--accent-strong), 0 0 12px rgba(159, 183, 170, 0.25); }
.pocket-item.is-ageing { background: var(--gui-tint-ageing-bg, linear-gradient(160deg, rgba(199, 154, 91, 0.16), rgba(199, 154, 91, 0.07))), #1b1f20; border-color: var(--gui-tint-ageing-border, rgba(199, 154, 91, 0.35)); }
.pocket-item.is-stale { background: var(--gui-tint-stale-bg, linear-gradient(160deg, rgba(199, 154, 91, 0.36), rgba(199, 154, 91, 0.18))), #1b1f20; border-color: var(--gui-tint-stale-border, rgba(199, 154, 91, 0.7)); }
.pocket-item.is-rotten { background: var(--gui-tint-rotten-bg, linear-gradient(160deg, rgba(192, 100, 90, 0.5), rgba(150, 60, 52, 0.32))), #1b1f20; border-color: var(--gui-tint-rotten-border, rgba(192, 100, 90, 0.85)); }
.pocket-item.is-used { background: var(--gui-tint-used-bg, linear-gradient(160deg, rgba(150, 165, 180, 0.2), rgba(150, 165, 180, 0.08))), #1b1f20; border-color: var(--gui-tint-used-border, rgba(150, 165, 180, 0.45)); }
/* Special things, in the satchel or the pockets (pack-view.js isSpecial(): anything of blackglass, or
   marked `special`, like the black bone): a violet tint. A pocket's food tints above win over it.
   Every tint here is tunable in Admin → GUI settings (BG-159, app/src/GuiTheme.php): each reads its
   --gui-tint-* property from /gui-settings.css, which defines it only once changed, so today's values
   (the fallbacks) stand until then. */
.pack-item.is-special, .pocket-item.is-special { background: var(--gui-tint-special-bg, linear-gradient(160deg, rgba(150, 125, 200, 0.3), rgba(150, 125, 200, 0.14))), #1b1f20; border-color: var(--gui-tint-special-border, rgba(160, 140, 210, 0.62)); }
.pack-item.is-special:hover, .pocket-item.is-special:hover { background: var(--gui-tint-special-hover-bg, linear-gradient(160deg, rgba(150, 125, 200, 0.36), rgba(150, 125, 200, 0.18))), #1b1f20; border-color: var(--gui-tint-special-hover-border, rgba(170, 150, 220, 0.85)); }
.pack-item.is-special.is-selected, .pocket-item.is-special.is-selected { border-color: var(--accent-strong); }
.pocket-item.is-over { border-style: dashed; border-color: var(--warn); }
.pocket-count {
  position: absolute; right: 2px; bottom: 1px; z-index: 1; pointer-events: none;
  font-size: 0.68rem; line-height: 1; color: var(--text-strong);
  text-shadow: 0 0 2px #000, 0 0 2px #000, 1px 1px 0 #000;
}
.pockets-over { margin: 0.5rem 0 0; }
.pocket-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; }

/* Flash on change (Jake, 2026-09-28, pack-view.js diffFlashes/applyFlashes): a gained item's cells and
   its box brighten in the pack's own green; a lost item's now-empty cells pulse a muted red instead;
   a counter whose count moved (an oatcake eaten) gets a lighter pulse than a whole new item. Moving an
   item by drag never flashes (see diffFlashes). Purely decorative (no layout shift: box-shadow and
   background only), so it plays once on the freshly built element with no JS cleanup needed - the
   next render replaces the DOM outright. The -static classes (prefers-reduced-motion, applyFlashes())
   hold the peak look without animating and are cleared by a timer instead. */
@keyframes pack-item-flash-gain {
  0%, 100% { box-shadow: none; }
  25%, 65% { box-shadow: 0 0 0 2px rgba(159, 183, 170, 0.7), 0 0 16px rgba(159, 183, 170, 0.5); }
  45% { box-shadow: 0 0 0 1px rgba(159, 183, 170, 0.35); }
}
@keyframes pack-cell-flash-gain {
  0%, 100% { background: var(--panel); box-shadow: none; }
  25%, 65% { background: rgba(159, 183, 170, 0.28); box-shadow: inset 0 0 0 2px rgba(159, 183, 170, 0.6); }
  45% { background: rgba(159, 183, 170, 0.12); box-shadow: inset 0 0 0 1px rgba(159, 183, 170, 0.3); }
}
@keyframes pack-cell-flash-loss {
  0%, 100% { background: var(--panel); box-shadow: none; }
  25%, 65% { background: rgba(192, 100, 90, 0.24); box-shadow: inset 0 0 0 2px rgba(192, 100, 90, 0.5); }
  45% { background: rgba(192, 100, 90, 0.1); box-shadow: inset 0 0 0 1px rgba(192, 100, 90, 0.25); }
}
@keyframes pack-counter-flash-pulse {
  0%, 100% { background: transparent; }
  40% { background: rgba(159, 183, 170, 0.22); }
}
.pack-item.pack-flash-gain { animation: pack-item-flash-gain 1.2s ease-in-out; }
.pack-cell.pack-flash-gain { animation: pack-cell-flash-gain 1.2s ease-in-out; }
.pack-cell.pack-flash-loss { animation: pack-cell-flash-loss 1.2s ease-in-out; }
.pack-counters li.pack-flash-pulse { animation: pack-counter-flash-pulse 0.7s ease-in-out; }
.pack-item.pack-flash-gain-static { box-shadow: 0 0 0 2px rgba(159, 183, 170, 0.7), 0 0 14px rgba(159, 183, 170, 0.45); }
.pack-cell.pack-flash-gain-static { background: rgba(159, 183, 170, 0.24); box-shadow: inset 0 0 0 2px rgba(159, 183, 170, 0.55); }
.pack-cell.pack-flash-loss-static { background: rgba(192, 100, 90, 0.2); box-shadow: inset 0 0 0 2px rgba(192, 100, 90, 0.5); }
.pack-counters li.pack-flash-pulse-static { background: rgba(159, 183, 170, 0.2); }
/* A pocket cell whose count moved: the same lighter pulse, as a ring so the state tint stays. */
@keyframes pocket-flash-pulse {
  0%, 100% { box-shadow: none; }
  40% { box-shadow: inset 0 0 0 2px rgba(159, 183, 170, 0.55), 0 0 10px rgba(159, 183, 170, 0.35); }
}
.pocket-item.pack-flash-pulse { animation: pocket-flash-pulse 0.7s ease-in-out; }
.pocket-item.pack-flash-pulse-static { box-shadow: inset 0 0 0 2px rgba(159, 183, 170, 0.55); }

/* ---- overlays and dialogs --------------------------------------------------------------------------- */
.overlay {
  position: fixed; inset: 0; z-index: 50; background: rgba(5, 6, 6, 0.975); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; overflow-y: auto;
  padding: max(1.5rem, env(safe-area-inset-top)) max(1.5rem, env(safe-area-inset-right)) max(1.5rem, env(safe-area-inset-bottom)) max(1.5rem, env(safe-area-inset-left));
}
.overlay[hidden] { display: none; }
.card { max-width: 34rem; width: 100%; text-align: center; animation: rise 0.8s ease-out both; }
.card .series { font-family: var(--font-mono); letter-spacing: 0.5em; text-transform: uppercase; color: var(--muted); font-size: 0.75rem; margin-bottom: 2rem; }
.card .ch-num { font-family: var(--font-mono); letter-spacing: 0.3em; color: var(--muted); font-size: 0.8125rem; text-transform: uppercase; }
.card .ch-title { font-family: var(--font-mono); font-size: clamp(1.4rem, 5vw, 2.2rem); letter-spacing: 0.22em; text-transform: uppercase; color: var(--text-strong); margin: 0.4rem 0 2rem; font-weight: 400; }
.card .complete { font-family: var(--font-mono); letter-spacing: 0.4em; color: var(--accent-strong); margin: -1rem 0 2rem; }
.card form, .card .actions { display: flex; flex-direction: column; gap: 0.75rem; align-items: stretch; max-width: 22rem; margin: 1.5rem auto 0; text-align: left; }
.card .actions .btn { width: 100%; }
.card .note { font-size: 0.875rem; color: var(--muted); margin-top: 1.25rem; }
/* The guest stop (start of Act III). */
.card .lead { font-size: 1.125rem; color: var(--text-strong); margin: 0 0 0.9rem; }
.card.guest-stop p { max-width: 30rem; margin-left: auto; margin-right: auto; }
.card .note a { color: var(--accent); }

/* "Choose your Journey" (js/ui/choose-journey.js): a quiet list of doorways, one column. */
.overlay:has(.card.choose) { align-items: flex-start; }
.card.choose { margin: auto 0; max-width: 36rem; }
.card.choose .ch-title { margin-bottom: 1.6rem; outline: none; font-size: clamp(1.15rem, 5vw, 2.2rem); }
.journeys { list-style: none; margin: 0; padding: 0; text-align: left; border-top: 1px solid var(--line); }
.journey { border-bottom: 1px solid var(--line); }
.journey-door {
  display: flex; flex-direction: column; gap: 0.35rem; width: 100%; text-align: left;
  background: none; border: 0; border-left: 2px solid transparent; color: var(--text);
  font: inherit; padding: 1rem 0.9rem; cursor: pointer;
}
button.journey-door:hover, button.journey-door:focus-visible { background: var(--panel); border-left-color: var(--accent); outline: none; }
.journey.is-open button.journey-door { border-left-color: var(--accent); }
.journey-who { font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-strong); }
.journey-role { color: var(--muted); }
.journey-unreleased { color: var(--warn); letter-spacing: 0.08em; text-transform: none; } /* development only */
.journey-line { font-family: var(--story-font); font-style: italic; font-size: 1rem; line-height: 1.45; color: var(--text); }
.journey-more { padding: 0 0.9rem 1.1rem calc(0.9rem + 2px); }
.journey-more p { margin: 0 0 0.6rem; line-height: 1.5; }
.journey-fullname { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.journey-home { font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.06em; color: var(--muted); }
.journey-intro { font-family: var(--story-font); font-size: 1rem; color: var(--text); }
.journey-begin { margin-top: 0.4rem; min-width: 9rem; }
.journey.is-unknown .journey-door { cursor: default; }
.journey.is-unknown .journey-who, .journey.is-unknown .journey-line { color: var(--faint); }
.journey-tick { color: var(--accent); font-weight: 700; }
.journey-completed { display: block; margin-top: 0.1rem; }
.journey-completed-note { display: block; font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.04em; color: var(--muted); }
.journey-completed-summary { display: block; font-family: var(--story-font); font-style: italic; font-size: 0.9rem; line-height: 1.4; color: var(--text); margin-top: 0.15rem; }
.journey-completed-summary strong { font-style: normal; color: var(--text-strong); }
.journey-completed-more { font-style: normal; color: var(--faint); }
.card.choose .note { text-align: center; }

/* A gated protagonist unlocked and not yet begun (registry `requires`, e.g. Nia; Jake, 2026-09-28,
   restyled 2026-09-30): a gold border with a gentle glow that breathes every 1.8 s, drawing the eye
   without moving anything (js/ui/choose-journey.js, continue-journey.js). It ends when a Journey with
   her exists, and she is then an ordinary card. The landing page's twin is .fragment-journey.is-unlocked
   (landing.css). Reduced motion: a steady gold border, no animation. */
.journey.journey-card--new { border: 1px solid #d4af37; box-shadow: 0 0 6px rgba(212, 175, 55, 0.25); animation: journey-card-new-pulse 1.8s ease-in-out infinite; }
.journey-newly { color: #d4af37; font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase; }
@keyframes journey-card-new-pulse {
  0%, 100% { border-color: #d4af37; box-shadow: 0 0 4px rgba(212, 175, 55, 0.2); }
  50% { border-color: #f0d271; box-shadow: 0 0 16px rgba(212, 175, 55, 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .journey.journey-card--new { animation: none; box-shadow: none; }
}
@media (max-width: 30rem) {
  .journey-door { padding: 0.9rem 0.6rem; }
  .journey-more { padding: 0 0.6rem 1rem calc(0.6rem + 2px); }
  .journey-begin { width: 100%; }
}

.menu-list { display: flex; flex-direction: column; gap: 0.5rem; }
.menu-list .btn { justify-content: flex-start; width: 100%; }
.menu-list hr { border: 0; border-top: 1px solid var(--line); margin: 0.5rem 0; width: 100%; }
.panel.slot { padding: 0.75rem; }
.slot-actions { margin-top: 0.5rem; }

.settings-dialog { width: min(32rem, calc(100vw - 2rem)); }
.settings-grid { display: flex; flex-direction: column; gap: 1.1rem; }
.settings-grid fieldset { border: 0; padding: 0; margin: 0; }
.settings-grid legend { margin-bottom: 0.4rem; }
.settings-grid .settings-heading {
  margin: 0.4rem 0 -0.3rem; padding-top: 0.9rem; border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 0.75rem; font-weight: 400; letter-spacing: 0.22em; text-transform: uppercase; color: var(--text-strong);
}
.settings-grid .settings-heading:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* "Play music" reads like the other checkboxes, not like a field's small caps label. */
.settings-grid .field label.check { font-family: inherit; font-size: 0.9375rem; letter-spacing: normal; text-transform: none; color: var(--text); }
.font-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; }
.font-choice { display: flex; gap: 0.5rem; align-items: center; border: 1px solid var(--line-strong); border-radius: var(--radius); padding: 0.5rem 0.6rem; cursor: pointer; }
.font-choice:has(input:checked) { border-color: var(--accent); background: rgba(159, 183, 170, 0.07); }
.font-sample { font-size: 1rem; }
.seg-inline { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.seg-inline label { display: inline-flex; gap: 0.35rem; align-items: center; cursor: pointer; }
.settings-grid input[type="range"] { width: 100%; accent-color: var(--accent); }
.settings-preview { font-family: var(--story-font); font-size: var(--story-size); line-height: var(--story-leading); color: var(--text); border-left: 2px solid var(--line-strong); padding-left: 0.8rem; }

/* ---- phones and narrow windows ------------------------------------------------------------------------ */
.mobile-tabs { display: none; }

@media (max-width: 62rem) {
  .game-shell { grid-template-rows: auto minmax(0, 1fr) auto; padding-bottom: 0; }
  .game-main, .game-main[data-panel="closed"] { grid-template-columns: minmax(0, 1fr); }
  .game-main[data-view="story"] .pane-side { display: none; }
  .game-main:not([data-view="story"]) .pane-story { display: none; }
  .game-main:not([data-view="story"]) .pane-side { display: flex; border-left: 0; }
  .game-main .panel-rail, .game-main[data-panel="closed"] .panel-rail { display: none; }
  .pane-splitter { display: none; }
  .side-tabs { display: none; }
  .mobile-tabs { display: flex; border-top: 1px solid var(--line); background: var(--bg); padding-bottom: env(safe-area-inset-bottom); }
  .update-notice { bottom: calc(3.9rem + env(safe-area-inset-bottom)); } /* above the tab bar (js/shell/pwa.js) */
  .mobile-tabs button {
    flex: 1; background: none; border: 0; color: var(--muted); padding: 0.85rem 0.25rem;
    font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.14em; text-transform: uppercase; cursor: pointer;
  }
  .mobile-tabs button[aria-selected="true"] { color: var(--text-strong); box-shadow: inset 0 2px 0 var(--accent); }
  /* Belongings and Recollections (BG-145) are longer words than Pack and Journal: each tab takes the room
     its word needs, on one line with its dot, and the spacing closes up on the narrowest phones. */
  .mobile-tabs button { flex: 1 1 auto; min-width: 0; white-space: nowrap; }
  .game-bar .fragment-name { display: none; }
  .story-tail { height: 30vh; }

  /* Travel on phones/narrow windows: the Story view (and its travel veil) stays on screen, and the
     live map is shown full-bleed behind it instead of switching to the Map tab — see game-view.js
     openMapForTravel(). The map (.pane-side) is laid over the whole game-main area, one step below
     the story pane, which is given a transparent background so the map shows through; the veil's
     own background is lightened so it reads as translucent rather than opaque. */
  .game-main.travel-peek { position: relative; }
  .game-main.travel-peek[data-view="story"] .pane-side { display: flex; position: absolute; inset: 0; z-index: 1; border-left: 0; }
  .game-main.travel-peek .pane-story { position: relative; z-index: 2; background: transparent; }
  .game-main.travel-peek .pane-story.travelling .story-scroll,
  .game-main.travel-peek .pane-story.travelling .story-head { visibility: hidden; }
  /* The card sits at the foot so the middle of the map, where the player is centred, stays clear. */
  .game-main.travel-peek .travel-veil {
    align-items: flex-end; padding-bottom: 3.5rem;
    background: linear-gradient(to top, rgba(9, 10, 11, 0.92) 0%, rgba(9, 10, 11, 0.6) 28%, rgba(9, 10, 11, 0.05) 55%, transparent 100%);
  }
  .game-main.travel-peek .travel-card { padding: 0.75rem 1rem; }
}
@media (max-width: 40rem) {
  .game-bar { gap: 0.35rem; padding: 0.35rem 0.5rem; }
  .game-bar .wordmark { letter-spacing: 0.2em; }
  .save-status .long { display: none; }
  .save-status .short { display: inline; }
  .story-scroll { padding: 0 1rem; }
  .story-head { padding: 0.5rem 1rem; }
}
/* The narrowest phones (360–415 px): the save state is shown by its dot alone (its words stay in the
   live region for screen readers), so Save, ♪, Aa and the menu still fit beside the wordmark. */
@media (max-width: 26rem) {
  .game-bar { gap: 0.25rem; }
  .game-bar .icon-btn { min-width: 2.1rem; }
  .save-status .short { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
}

/* Development screenshots (?anim=0): headless capture does not advance CSS animations. */
html.no-anim *, html.no-anim *::before, html.no-anim *::after { animation: none !important; transition: none !important; }

.settings-grid .font-choice, .settings-grid .seg-inline label { text-transform: none; letter-spacing: normal; font-family: var(--font-sans); font-size: 0.9rem; color: var(--text); }
.settings-grid .font-sample { font-size: 1.05rem; }

/* Reading font everywhere text is read, not only in the story. Small uppercase labels, tabs and
   the map itself keep the monospaced face. */
.side-page, .dialog, .card, .map-card, .map-info { font-family: var(--story-font); }
.entries .title, .entries .former, .pack-detail .title, .pack-counters, .journal-search {
  font-family: var(--story-font); letter-spacing: 0;
}
.entries .title { font-size: 1em; font-weight: 600; }

/* Interactive terms in the story: things with a journal entry. */
.term {
  font: inherit; font-weight: 700; color: var(--text-strong); background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; text-decoration: underline dotted rgba(159, 183, 170, 0.55); text-underline-offset: 0.2em;
  text-decoration-thickness: 1px; border-radius: 2px;
}
.term:hover, .term:focus-visible { color: var(--accent-strong); text-decoration-color: var(--accent); outline: none; }
.passage.past .term { font-weight: 600; }
.term-card {
  position: absolute; z-index: 20; background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55); padding: 0.75rem 0.9rem; font-family: var(--story-font);
  font-size: calc(var(--story-size) * 0.82); line-height: 1.5; color: var(--text);
}
.term-card[hidden] { display: none; }
.term-card-head { display: flex; align-items: baseline; gap: 0.5rem; }
.term-card .title { flex: 1; font-weight: 700; color: var(--text-strong); }
.term-card .former { font-size: 0.85em; color: var(--faint); margin-top: 0.15rem; }
.term-card .former s { margin-right: 0.4rem; }
.term-card p { margin: 0.4rem 0 0; }
.term-card .standing { color: var(--accent); font-style: italic; }
.term-card .btn { margin-top: 0.6rem; }
.term-close { background: none; border: 0; color: var(--muted); font-size: 1.1rem; cursor: pointer; line-height: 1; }
.term-close:hover { color: var(--text-strong); }

/* Questions already asked in a conversation; a talk asked out, or an action with nothing new to
   show (disabled), in a place's list. */
.choice.is-asked .choice-label { color: var(--gui-asked-ink, var(--faint)); } /* dimming: Admin → GUI settings (BG-159) */
.choice.is-asked:disabled { cursor: default; }
.choice.is-asked:hover:not(:disabled) .choice-label { color: var(--muted); }
.asked-note {
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--faint); border: 1px solid var(--line); border-radius: 2px; padding: 0 0.35rem; white-space: nowrap; align-self: center;
}

/* Locations with nothing new for now. */
.tick { color: var(--ok); font-family: var(--font-mono); font-weight: 700; }

/* Travel: the story fades out while the protagonist is on the move. */
.story-scroll, .story-head { transition: opacity 0.45s ease, filter 0.45s ease; }
.pane-story.travelling .story-scroll, .pane-story.travelling .story-head { opacity: 0.06; filter: blur(2px); }
.travel-veil {
  position: absolute; inset: 0; z-index: 15; display: flex; align-items: center; justify-content: center;
  cursor: pointer; animation: veil-in 0.45s ease both;
  background: radial-gradient(ellipse at center, rgba(10, 11, 12, 0.92) 0%, rgba(10, 11, 12, 0.55) 60%, rgba(10, 11, 12, 0.2) 100%);
}
.travel-veil[hidden] { display: none; }
.travel-veil.leaving { animation: veil-out 0.45s ease both; }
@keyframes veil-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes veil-out { from { opacity: 1; } to { opacity: 0; } }
.travel-card { text-align: center; padding: 1.5rem; max-width: 30rem; }
.travel-kicker { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.3em; text-transform: uppercase; color: var(--muted); }
.travel-dest { font-family: var(--story-font); font-size: calc(var(--story-size) * 1.35); color: var(--text-strong); margin: 0.6rem 0 0.9rem; }
.travel-via { font-style: italic; font-size: 0.8em; color: var(--text); }
.travel-time { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.12em; color: var(--faint); margin-top: 0.8rem; }
.travel-dots { display: inline-flex; gap: 0.5rem; }
.travel-dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); opacity: 0.25; animation: travel-dot 1.2s ease-in-out infinite; }
.travel-dots span:nth-child(2) { animation-delay: 0.2s; }
.travel-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes travel-dot { 0%, 100% { opacity: 0.2; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-3px); } }
.travel-note { font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin-top: 0.5rem; }
.travel-remain { font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.05em; color: var(--faint); margin-top: 0.9rem; }
.travel-progress { width: 11rem; max-width: 60vw; height: 2px; background: var(--line); border-radius: 2px; margin: 0.5rem auto 0; overflow: hidden; }
.travel-progress-bar { height: 100%; width: 0; background: var(--accent); }
.travel-skip {
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint); margin-top: 1.1rem; opacity: 0.7;
}

/* ---- travel: desktop full-screen map -------------------------------------------------------
   On wide layouts (the .mobile-tabs breakpoint above never applies .travel-expand — game-view.js
   only adds it when the mobile tab bar is hidden), travel expands the map pane over the whole
   game area — story pane, splitter and all — the same full-bleed composition as the phone's
   .travel-peek above, just reached from a grid layout instead of a single column. Both panes are
   pinned to the game-main box instead of their grid column/track, so the map fills the whole area
   regardless of the side panel's own width, and the story pane's (now-transparent, emptied-out)
   box no longer clips the veil to its own column. See game-view.js openMapForTravel()/
   restoreAfterTravel(). */
.game-main.travel-expand { position: relative; }
.game-main.travel-expand .pane-story { position: absolute; inset: 0; z-index: 2; background: transparent; }
.game-main.travel-expand .pane-story.travelling .story-scroll,
.game-main.travel-expand .pane-story.travelling .story-head { visibility: hidden; }
.game-main.travel-expand .pane-splitter,
.game-main.travel-expand .panel-rail { display: none; }
/* The map pane starts docked at its normal side-panel rect (so adding .travel-expand alone causes
   no visible jump) and, once .travel-expanded also lands a frame later, animates its left edge
   out to the full width over ~0.35s — an actual, not merely faded, expansion. Collapsing back is
   instant (restoreAfterTravel() drops both classes together): the travel veil is still fading out
   on top of it at that point, which masks the snap the same way it does on the phone. Reduced
   motion (base.css) already collapses this transition's duration to near-zero. */
.game-main.travel-expand .pane-side {
  position: absolute; top: 0; right: 0; bottom: 0; z-index: 1; display: flex; border-left: 0;
  left: calc(100% - var(--side-width) - 6px);
  transition: left 0.35s ease;
}
.game-main.travel-expand.travel-expanded .pane-side { left: 0; }
/* Card at the foot, gradient behind it, so the middle of the map — where the player is centred —
   stays clear. */
.game-main.travel-expand .travel-veil {
  align-items: flex-end; padding-bottom: 3.5rem;
  background: linear-gradient(to top, rgba(9, 10, 11, 0.92) 0%, rgba(9, 10, 11, 0.6) 28%, rgba(9, 10, 11, 0.05) 55%, transparent 100%);
}
.game-main.travel-expand .travel-card { padding: 0.75rem 1rem; }
/* Over the map (desktop and phone), the card sits on its own dark panel so map labels under it
   never compete with its text. */
.game-main.travel-expand .travel-card,
.game-main.travel-peek .travel-card {
  background: rgba(9, 10, 11, 0.86); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 0.9rem 1.4rem; box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
}

/* Owner preview (registry status `preview`; docs/fragment-2/BUILD.md §1.4): a quiet chip in the game
   bar, only ever shown to owners. Stays visible on phones, where the fragment name is hidden. */
.game-bar .preview-chip {
  flex: 0 0 auto; margin-left: 0.4rem; padding: 0.05rem 0.4rem; white-space: nowrap;
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--warn); border: 1px solid var(--warn); border-radius: 2px;
}

/* "Which Journey goes on?" (js/ui/continue-journey.js): the finished Journey's ending title. */
.continue-journey .journey-ending { font-style: italic; }
/* A Journey whose way on is not open yet, and a protagonist who has not finished the earlier
   fragment (Jake, 2026-09-28): shown, quieter, with no action. */
.continue-journey .journey-not-yet { color: var(--muted); letter-spacing: 0.08em; }
.continue-journey .journey.is-unfinished .journey-door { cursor: default; }
.continue-journey .journey.is-unfinished .journey-who,
.continue-journey .journey.is-unfinished .journey-line { color: var(--muted); }
