/* Turn entries, roll breakdown, health loss, act headers */

.turn-entry { border-left: 2px solid var(--border-color); padding-left: 0.75rem; }
.turn-entry.prologue { border-left-color: var(--theme-accent); }
.turn-entry.success { border-left-color: var(--color-success); }
.turn-entry.partial { border-left-color: var(--color-partial); }
.turn-entry.failure { border-left-color: var(--color-failure); }
.turn-entry.ending { border-left-color: var(--theme-accent); background: linear-gradient(180deg, color-mix(in srgb, var(--theme-accent) 12%, transparent), transparent); padding: 0.8rem 0.75rem; border-radius: 2px; }
.turn-entry.ending.completed { border-left-color: var(--theme-accent); background: linear-gradient(180deg, color-mix(in srgb, var(--theme-accent) 12%, transparent), transparent); }
.turn-entry.ending.failed { border-left-color: var(--color-failure); background: linear-gradient(180deg, rgba(144, 48, 48, 0.12), transparent); }
.turn-ending-label { font-family: 'Cinzel', serif; font-size: 0.6rem; letter-spacing: 0.3em; color: var(--theme-accent); text-transform: uppercase; margin-bottom: 0.6rem; }
.turn-entry.ending.completed .turn-ending-label { color: var(--theme-accent); }
.turn-entry.ending.failed .turn-ending-label { color: var(--color-failure-text); }
.turn-action { font-family: 'Lora', Georgia, serif; font-style: italic; color: var(--text-muted); font-size: 0.84rem; margin-bottom: 0.45rem; }
.turn-narrative { font-family: var(--theme-font); color: var(--theme-text); line-height: 1.7; font-size: 0.92rem; white-space: pre-wrap; }
/* The demo's opening types itself out (typewriter_controller.js). What the
   turn shows under it, the place's card first, keeps its room but waits for
   the last line, then fades in. */
.turn-narrative[data-controller~="typewriter"] ~ * { transition: opacity 0.4s ease; }
.turn-narrative.is-typing ~ * { visibility: hidden; opacity: 0; }
.turn-meta { font-family: 'Cinzel', serif; font-size: 0.58rem; letter-spacing: 0.2em; color: var(--text-dim); margin-top: 0.4rem; text-transform: uppercase; }
.turn-time { font-family: 'Cinzel', serif; font-size: 0.58rem; letter-spacing: 0.2em; color: var(--text-dim); margin-bottom: 0.3rem; text-transform: uppercase; }
/* The value column may shrink below its natural width, so on a phone the long
   XP row wraps inside the turn instead of running off the screen. Where there
   is room every row keeps to one line, as before. */
.roll-breakdown { display: grid; grid-template-columns: max-content minmax(0, max-content); column-gap: 1.2rem; row-gap: 0.18rem; align-items: center; width: max-content; max-width: 100%; margin-top: 0.4rem; margin-bottom: 0.7rem; font-family: 'Cinzel', serif; font-size: 0.7rem; letter-spacing: 0.06em; color: var(--text-muted); }
.roll-row-label { color: var(--text-dim); text-transform: uppercase; font-size: 0.58rem; letter-spacing: 0.15em; }
.roll-row-value { text-align: right; color: var(--text-mid); }
.roll-divider { grid-column: 1 / -1; height: 1px; background: var(--line-dim); opacity: 0.3; margin: 0.15rem 0; }
.roll-total { font-weight: 600; color: var(--text-mid); }
.roll-threshold { color: var(--text-mid); font-weight: 600; }
.roll-verdict { display: inline-block; font-size: 0.6rem; letter-spacing: 0.15em; padding: 0.1rem 0.35rem; border-radius: 1px; }
.roll-verdict.success { color: var(--color-success); border: 1px solid var(--color-success); }
.roll-verdict.partial { color: var(--color-partial); border: 1px solid var(--color-partial); }
/* The words' red, which the theme lifts to 4.5:1 (_theme_style): the fixed
   #903030 was about 2:1 on the dark themes. */
.roll-verdict.failure { color: var(--color-failure-text); border: 1px solid var(--color-failure-text); }
.roll-difficulty { font-size: 0.58rem; color: var(--text-dim); letter-spacing: 0.1em; }
/* The XP gain alone. A step toward the goal reads in the success colour, a
   turning point in the theme's accent, larger, as the level-up line does. */
.roll-xp-gain { font-weight: 600; color: var(--text-mid); white-space: nowrap; }
.roll-xp-gain.positive { color: var(--color-success); }
.roll-xp-gain.major { color: var(--theme-accent); font-size: 0.8rem; letter-spacing: 0.1em; }
/* The roll that reaches a level: one line across both columns, in the theme's
   accent so it stands apart from the arithmetic above it. */
.roll-level-up { grid-column: 1 / -1; margin-top: 0.15rem; color: var(--theme-accent); text-transform: uppercase; font-size: 0.62rem; font-weight: 600; letter-spacing: 0.2em; }
.health-loss { font-family: 'Cinzel', serif; font-size: 0.62rem; letter-spacing: 0.12em; color: var(--color-danger-text); margin-top: 0.3rem; display: flex; align-items: center; gap: 0.3rem; }
.health-loss-icon { font-size: 0.7rem; }
.health-loss-value { font-weight: 600; }
.health-gain { font-family: 'Cinzel', serif; font-size: 0.62rem; letter-spacing: 0.12em; color: var(--color-heal); margin-top: 0.3rem; display: flex; align-items: center; gap: 0.3rem; }
.health-gain-icon { font-size: 0.7rem; }
.health-gain-value { font-weight: 600; }

/* Player continuation — resumes the previous turn's moment, so it reads as one
   passage: pull it up over the .turn-log flex gap and drop the left rule, but
   keep the 2px so the text stays aligned with the turn above. */
.turn-entry.continuation-player { margin-top: -1rem; border-left-color: transparent; }

/* Continue arrow. Only ever shown on the newest entry — while a turn streams,
   the JS placeholder is #turn-log's last child, so this hides itself and comes
   back when the finished turn is appended. */
.turn-continue { display: none; margin-top: 0.6rem; padding: 0.3rem 0.7rem; background: transparent; border: 1px solid var(--border-color); border-radius: 1px; color: var(--text-mid); font-family: 'Cinzel', serif; font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase; line-height: 1.2; cursor: pointer; transition: color 0.15s, border-color 0.15s; }
@media (hover: hover) {
  .turn-continue:hover { color: var(--theme-accent); border-color: color-mix(in srgb, var(--theme-accent) 55%, transparent); }
}
.turn-continue:disabled { opacity: 0.4; cursor: default; }
.turn-entry:last-child .turn-continue { display: inline-block; }

/* "Load earlier" sits at the top of #turn-log, above the oldest loaded turn.
   The wrapper is always in the DOM — it is the stream target the next page is
   inserted after — so it is taken out of the flex flow entirely: empty it adds
   no box and no gap, and holding the button it hands the button through as the
   flex item. (:empty would not do, since ERB leaves whitespace inside it.) */
#load-earlier { display: contents; }
.load-earlier { display: block; margin: 0 auto; padding: 0.25rem 0.9rem; background: transparent; border: 1px solid color-mix(in srgb, var(--border-color) 70%, transparent); border-radius: 1px; color: var(--text-dim); font-family: 'Cinzel', serif; font-size: 0.58rem; letter-spacing: 0.2em; text-transform: uppercase; cursor: pointer; transition: color 0.15s, border-color 0.15s; }
@media (hover: hover) {
  .load-earlier:hover { color: var(--theme-accent); border-color: color-mix(in srgb, var(--theme-accent) 55%, transparent); }
}
.load-earlier:disabled { opacity: 0.4; cursor: default; }

/* Turn failure notice — lives outside #turn-log so it can't displace the
   newest .turn-entry and hide the continue arrow. */
/* The danger red pulled toward the theme's text, so it clears 4.5:1 on the
   dark themes (#c84040 alone is 3.95:1 on #0d0d0d) and darkens on the light
   ones rather than washing out. */
.turn-error { font-family: 'Cinzel', serif; font-size: 0.7rem; letter-spacing: 0.1em; color: color-mix(in srgb, var(--color-danger-text) 70%, var(--theme-text)); text-transform: uppercase; padding: 0.5rem 1rem; }
.turn-error:empty { display: none; }
/* A notice the player arrived with (games/show), where a phone will see it. */
.game-notice { margin: 0; padding: 0.5rem 1rem; font-family: 'Lora', Georgia, serif; font-style: italic; font-size: 0.8rem; color: var(--text-mid); border-top: 1px solid var(--border-subtle); }
.turn-error-reload { margin-left: 0.6rem; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; background: none; border: 1px solid currentColor; border-radius: 2px; padding: 0.15rem 0.5rem; cursor: pointer; }

/* Loading indicator — three pulsing dots */
.loading-indicator {
  display: flex;
  gap: 0.35rem;
  padding: 0.5rem 0;
}
.loading-indicator span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-muted, #666);
  animation: loadPulse 1.4s ease-in-out infinite;
}
.loading-indicator span:nth-child(2) { animation-delay: 0.2s; }
.loading-indicator span:nth-child(3) { animation-delay: 0.4s; }

@keyframes loadPulse {
  0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

/* Scene intro (inline after narrative) */
/* The picture in the story, under the header that names the place. */
.scene-card-image .lightbox-trigger { height: auto; }
.scene-card-image-img { display: block; width: 100%; max-width: 640px; height: auto; aspect-ratio: 16 / 9; object-fit: cover; margin: 0.5rem 0; border: 1px solid var(--border-subtle); }
.scene-card-image .scene-image-placeholder { max-width: 640px; margin: 0.5rem 0; }
.scene-intro {
  margin-top: 0.8rem;
  font-family: var(--theme-font);
  color: var(--theme-text);
  font-size: 0.92rem;
  line-height: 1.7;
}
.scene-intro-header {
  font-family: 'Cinzel', serif;
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  color: var(--theme-accent);
  text-transform: uppercase;
  text-align: center;
  margin-bottom: 0.4rem;
}
.scene-intro-description {
  margin-bottom: 0.5rem;
  opacity: 0.85;
}
.scene-intro-entity {
  color: var(--text-mid);
}
.scene-intro-entity strong { color: var(--theme-text); }

/* The demo openings' art */
.turn-image { margin: 0.6rem 0; text-align: center; }
.turn-image img { max-width: 100%; max-height: 280px; border-radius: 4px; opacity: 0.9; }
/* The picture's own size, so only the picture opens the viewer. */
.turn-image .turn-image-trigger { display: inline-block; width: auto; max-width: 100%; }

/* Hints — a teaching note attached to the turn it came due on. Deliberately
   unlike the prose around it: sans-serif, indented behind a marker, so a
   reader's eye can skip the whole block without having to read a line of it
   first and discover it is not the story. */
.turn-hint {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  margin-top: 0.9rem;
  padding: 0.7rem 0.85rem;
  border-left: 2px solid var(--theme-accent);
  background: rgba(127, 127, 127, 0.07);
  border-radius: 0 3px 3px 0;
}
.turn-hint-icon {
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  line-height: 1.05rem;
  text-align: center;
  border-radius: 50%;
  border: 1px solid var(--theme-accent);
  color: var(--theme-accent);
  font-size: 0.68rem;
  font-weight: 700;
  margin-top: 0.1rem;
}
.turn-hint-body { flex: 1 1 auto; min-width: 0; }
.turn-hint-text {
  margin: 0;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 0.78rem;
  line-height: 1.5;
  color: var(--text-muted, #888);
}
.turn-hint-dismiss {
  margin-top: 0.4rem;
  padding: 0;
  background: none;
  border: none;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--text-muted, #888);
  opacity: 0.65;
  cursor: pointer;
  text-decoration: underline;
}
@media (hover: hover) {
  .turn-hint-dismiss:hover { opacity: 1; }
}
.turn-hint-close {
  flex: 0 0 auto;
  align-self: flex-start;
  padding: 0 0.15rem;
  background: none;
  border: none;
  line-height: 1;
  font-size: 0.95rem;
  color: var(--text-muted, #888);
  opacity: 0.45;
  cursor: pointer;
}
@media (hover: hover) {
  .turn-hint-close:hover { opacity: 1; }
}

/* Someone walking into the room the player is standing in: the picture beside
   their name, under the prose that introduced them. A card rather than a plate
   — a 2:3 portrait across the column is most of a phone screen, and this is a
   beat in the story rather than an illustration of it. */
.entrance {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin: 0.7rem 0;
  padding: 0.5rem 0.6rem;
  border-left: 2px solid var(--theme-accent);
  background: color-mix(in srgb, var(--panel-bg) 45%, transparent);
}
/* Kept on the page with nothing in it so a redraw has somewhere to land. */
.entrance-empty { display: none; }
/* The width is load-bearing, not decoration: .lightbox-trigger is width:100% by
   default (base.css), which in a flex row takes the whole width and squeezes
   the name off the screen. */
.entrance .lightbox-trigger { width: 4.5rem; height: 6.75rem; padding: 0; border: 0; background: none; cursor: zoom-in; flex: 0 0 auto; }
.entrance-portrait,
.entrance-placeholder {
  display: block;
  width: 4.5rem;
  height: 6.75rem;
  object-fit: cover;
  border: 1px solid var(--border-subtle);
  background: color-mix(in srgb, var(--panel-bg) 70%, transparent);
}
.entrance-placeholder { position: relative; overflow: hidden; flex: 0 0 auto; border-style: dashed; }
.entrance-placeholder::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--text-muted) 14%, transparent) 50%, transparent 80%);
  transform: translateX(-100%);
  animation: scene-image-shimmer 1.8s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .entrance-placeholder::before { animation: none; } }
/* No shimmer: nothing is coming until next month or a bigger plan. */
.entrance-spent::before { content: none; }
.entrance-text { min-width: 0; }
.entrance-name { font-family: 'Cinzel', serif; font-size: 0.78rem; color: var(--text-bright); letter-spacing: 0.04em; }
.entrance-dead { font-family: 'Lora', Georgia, serif; font-style: italic; font-size: 0.72rem; color: var(--text-dim); margin-top: 0.2rem; }

/* A face on an arrival card, inline with the name it belongs to. Small, because
   the card is a list of who is here rather than a gallery. */
.card-face { display: inline-block; vertical-align: -0.35rem; margin-right: 0.35rem; }
.card-face:empty { display: none; }
.card-face .lightbox-trigger { display: block; width: 1.5rem; height: 1.5rem; padding: 0; border: 0; background: none; cursor: zoom-in; }
.card-face-img {
  display: block;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  border: 1px solid var(--border-subtle);
  object-fit: cover;
}

/* Out of tokens, in the action form's place (games/_out_of_tokens). */
.oot-card { padding: 0.9rem 1rem; border-top: 1px solid var(--border-color); text-align: center; font-family: 'Lora', Georgia, serif; }
.oot-card-title { color: var(--theme-text); font-style: italic; font-size: 0.9rem; margin: 0 0 0.35rem; }
.oot-card-line { color: var(--text-muted); font-size: 0.8rem; margin: 0.2rem 0 0; }
.oot-card-line a { color: var(--theme-accent); }
.oot-card-line a.oot-card-primary { display: inline-block; margin: 0.2rem 0 0.1rem; padding: 0.35rem 0.8rem; border: 1px solid var(--theme-accent); text-decoration: none; font-style: normal; }

/* The story has ended (games/_game_end), in the action form's place. */
.game-end { padding: 0.9rem 1rem 1rem; border-top: 1px solid var(--border-color); text-align: center; font-family: 'Lora', Georgia, serif; }
.game-end-title { margin: 0 0 0.3rem; font-family: 'Cinzel', serif; font-weight: 400; font-size: 0.8rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--theme-accent); }
.game-end--failed .game-end-title { color: var(--color-failure-text); }
/* Focused by script when the story ends live, never tabbed to (tabindex=-1). */
.game-end-title:focus { outline: none; }
.game-end-body { margin: 0 auto 0.75rem; max-width: 34rem; font-style: italic; font-size: 0.85rem; color: var(--text-mid); }
.game-end-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.4rem; }
.game-end-actions .panel-action-btn { width: auto; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; text-decoration: none; }
.game-end-actions .game-end-primary { color: var(--theme-accent); border-color: var(--theme-accent); background: color-mix(in srgb, var(--theme-accent) 10%, transparent); }
@media (max-width: 768px) {
  .game-end-actions > * { flex: 1 1 0; }
  .game-end-actions > .game-end-primary { flex-basis: 100%; }
}
@media (pointer: coarse) { .game-end-actions .panel-action-btn { min-height: 44px; } }

/* "New text below", for a reader scrolled up the story (game#onLogChanged). */
.turn-log-jump-anchor { position: relative; height: 0; }
.turn-log-jump { position: absolute; left: 50%; bottom: 0.6rem; transform: translateX(-50%); z-index: 2; padding: 0.3rem 0.8rem; border: 1px solid var(--theme-accent); border-radius: 1rem; background: var(--panel-bg); color: var(--theme-accent); font-family: 'Cinzel', serif; font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase; cursor: pointer; box-shadow: 0 2px 10px color-mix(in srgb, var(--theme-bg) 70%, transparent); }
.turn-log-jump[hidden] { display: none; }

/* A phone reads at arm's length: 1rem is 16px there (base.css), so the story
   was 14.7px and its labels under 10px. The prose goes to 17px, and the small
   capitals round it come up to 0.68rem (10.9px), tracking less so they keep
   their width. */
@media (max-width: 768px) {
  .turn-narrative, .scene-intro { font-size: 1.0625rem; }
  .turn-action { font-size: 0.95rem; }
  .turn-meta, .turn-time, .roll-row-label, .roll-difficulty, .roll-verdict,
  .turn-ending-label, .roll-level-up, .health-loss, .health-gain,
  .load-earlier, .turn-log-jump, .turn-continue { font-size: 0.68rem; letter-spacing: 0.08em; }
}

/* On a wide screen a monospace theme ran 70-90 characters a line. The story
   keeps to 66, and a place's picture to the same measure, taken in the
   story's own font and size, so picture and text end on one edge. */
@media (min-width: 769px) {
  .turn-narrative, .scene-intro, .turn-action { max-width: 66ch; }
  .scene-card-image-img {
    font-family: var(--theme-font);
    font-size: 0.92rem;
    max-width: min(640px, 66ch);
  }
}
