/* Planning Block Choice Buttons Styling */

/* Composer choice type scale (rev-f9kno.7). ONE token drives the choice
   title, the pros/cons detail, and the Send label so they cannot drift apart:
   the operator's requirement is that ALL choice-text — composer rows AND the
   in-story planning-block buttons — render at the SAME size as the narrative
   prose (`#story-content p`, `font-size: 16px` inherited from <body>). The
   token lives at 1rem (== 16px) so this stays a single source of truth; if
   you ever need to step it down again, change ONLY this line. Historically
   this was set to 12.8px to make the composer row feel compact against the
   textarea; the operator reversed that decision on 2026-08-18 ("planning
   block and custom action text too small — make it same size as narrative
   text"), so the value is back at the body baseline. */
:root {
  --composer-choice-font: 1rem;
}

/* Risk-tinted planning-block (Direction 4, feat/risk-tinted-direction-4).
   The choice row's data-risk attribute surfaces the existing risk_level
   field (one of: safe | low | medium | high; VALID_RISK_LEVELS in
   narrative_response_schema.py). Three tokens cover the four values:
   safe=green, low/medium=risky=yellow, high=dangerous=red. The row gets a
   2px left border + ~7% bg tint via color-mix so the cue is visible without
   overpowering the existing safe/risky/dangerous text the renderer may add
   later. The helper var(--risk-rgb-<level>) holds the numeric RGB triple so
   color-mix works in `in srgb` syntax without parsing the hex. The
   fallback-form CSS uses both the named token AND a hex literal so a
   painter that strips the tokens (e.g. theme overrides) still renders the
   color, and a contract test pins the fallback chain end-to-end. */
:root {
  --risk-safe: #2ea043;
  --risk-risky: #d4a017;
  --risk-dangerous: #c93c3c;
  --risk-rgb-safe: 46 160 67;
  --risk-rgb-risky: 212 160 23;
  --risk-rgb-dangerous: 201 60 60;
}

/* Thinking text paragraph styling */
.planning-block-thinking {
  margin-bottom: 0.5rem;
}

/* Aggressively collapse vertical space below planning block choices */
.planning-block-choices {
  margin-bottom: 0 !important;
  padding-bottom: 0 !important;
}

.planning-block-choices + div,
.planning-block-choices + form,
.planning-block-choices + input,
.planning-block-choices + .form-group,
.planning-block-choices + .input-group {
  margin-top: 0 !important;
  padding-top: 0 !important;
}

/* Remove margin from parent if present */
.planning-block-choices:parent {
  margin-bottom: 0 !important;
  padding-bottom: 0 !important;
}

/* Individual choice button */
.choice-button {
  display: block;
  width: 100%;
  margin-bottom: 0.5rem;
  padding: 0.5rem 1rem;
  text-align: left;
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.15s ease;
  line-height: 1.4;
  color: #212529;
  box-shadow: none;
}

.choice-button:last-child {
  margin-bottom: 0.1rem;
}

/* Per-row disclosure (E1a, rev-f9kno.6, supersedes C4's always-expanded
   compact pros/cons line from rev-f9kno.2): each choice defaults to ONE
   line (title only); a sibling chevron button reveals pros/cons for THAT
   row only, independent of the others (ARIA APG Disclosure pattern, not
   the stricter exclusive-open Accordion -- multiple rows may be open at
   once). Unscoped so history and the composer -- which render the SAME
   markup via parsePlanningBlocks -- both get it; the composer-scoped
   overrides further below (.composer-choices .choice-row ...) handle the
   width/divider differences between the two contexts, same pattern the old
   .choice-body block used. */
.choice-row {
  margin-bottom: 0.5rem;
}

.choice-row:last-child {
  margin-bottom: 0.1rem;
}

/* Risk-tinted row (Direction 4). The data-risk attribute on the .choice-row
   div mirrors the LLM's risk_level (safe | low | medium | high). Four values
   fold into three colors: safe=green, low/medium=risky=yellow, high=
   dangerous=red. 2px left border + ~7% bg tint via color-mix; the tint is
   drawn on the row container (not the inner button) so hovering the title
   still uses the existing .choice-button hover state without double-tinting.
   The pad-left absorbs the 2px border so the title text does not shift from
   its existing baseline. */
.choice-row[data-risk="safe"] {
  border-left: 2px solid var(--risk-safe, #2ea043);
  background-color: color-mix(in srgb, var(--risk-safe, #2ea043) 7%, transparent);
}

.choice-row[data-risk="low"],
.choice-row[data-risk="medium"] {
  border-left: 2px solid var(--risk-risky, #d4a017);
  background-color: color-mix(in srgb, var(--risk-risky, #d4a017) 7%, transparent);
}

.choice-row[data-risk="high"] {
  border-left: 2px solid var(--risk-dangerous, #c93c3c);
  background-color: color-mix(in srgb, var(--risk-dangerous, #c93c3c) 7%, transparent);
}

.choice-head {
  display: flex;
  align-items: center;
}

/* The title button keeps the existing .choice-button visual language
   (background/hover/active/focus/disabled from the base rule below and the
   composer override further down) -- only its width changes, from 100% to
   flex:1, since it now shares its row with .chev-btn. */
.choice-row .choice-select {
  flex: 1;
  min-width: 0;
  width: auto;
  margin-bottom: 0;
}

.ctitle {
  font-size: var(--composer-choice-font, 1rem);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* When expanded, line-wrap the choice title so long choice texts are not cutoff */
.choice-row.open .ctitle {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  word-break: break-word;
}

.chev-btn {
  flex: 0 0 auto;
  width: 34px;
  align-self: stretch;
  background: transparent;
  border: none;
  border-left: 1px solid rgba(255, 255, 255, 0.06);
  color: var(--text-muted, #8a86a8);
  cursor: pointer;
  font-size: 11px;
}

.chev-btn:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-primary, #f0ecff);
}

.chev-btn i {
  transition: transform 0.15s;
  display: inline-block;
}

.choice-row.open .chev-btn i {
  transform: rotate(180deg);
}

.choice-detail {
  display: none;
  padding: 0 12px 9px 40px;
  /* PARITY with the choice title (rev-f9kno.7) — same token, never a literal. */
  font-size: var(--composer-choice-font, 1rem);
  color: var(--text-muted, #8a86a8);
}

.choice-row.open .choice-detail {
  display: block;
}

.choice-detail b {
  color: var(--text-secondary, #b8b4cf);
  font-weight: 600;
}

.choice-detail .pro {
  color: #86efac;
}

.choice-detail .con {
  color: #fca5a5;
}

.choice-button:hover {
  background: #e9ecef;
  border-color: #adb5bd;
}

.choice-button:active {
  background: #dee2e6;
}

/* Choice ID styling */
.choice-id {
  font-weight: bold;
  color: #0d6efd;
  margin-right: 0.5rem;
  font-family: 'Courier New', monospace;
}

/* Choice description */
.choice-description {
  color: #495057;
}

/* Disabled state when waiting for response */
.choice-button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  background: #e9ecef;
}

/* Custom choice button styling */
.choice-button-custom {
  background: linear-gradient(135deg, #f0f4ff 0%, #e0e8ff 100%);
  border-color: #6c757d;
  border-style: dashed;
}

.choice-button-custom:hover {
  background: linear-gradient(135deg, #e0e8ff 0%, #d0d8ff 100%);
  border-color: #495057;
}

.choice-button-custom .choice-id {
  color: #6c757d;
}

.choice-button-custom .choice-description {
  font-style: italic;
  color: #6c757d;
}

/* Custom action button - always shown at bottom of planning block choices */
.custom-action-button {
  background: transparent;
  border-style: dashed;
  border-color: #adb5bd;
  color: #6c757d;
  font-style: italic;
  margin-top: 0.25rem;
}

.custom-action-button:hover {
  background: #f8f9fa;
  border-color: #6c757d;
  color: #495057;
}

/* Error state for planning blocks */
.planning-block-error {
  background-color: #fff3cd;
  border: 1px solid #ffecb5;
  color: #856404;
  padding: 1rem;
  margin: 0.5rem 0;
  border-radius: 0.25rem;
}

.planning-block-error pre {
  background-color: rgba(0, 0, 0, 0.05);
  padding: 0.5rem;
  margin: 0.5rem 0;
  border-radius: 0.25rem;
  overflow-x: auto;
  font-size: 0.875rem;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* Styling for malformed content within error blocks */
.malformed-content {
  background-color: rgba(0, 0, 0, 0.05);
  padding: 0.75rem;
  margin: 0.5rem 0;
  border-radius: 0.25rem;
  border-left: 4px solid #ffecb5;
  font-family: monospace;
  font-size: 0.9rem;
  line-height: 1.4;
  overflow-x: auto;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* Responsive design */
@media (max-width: 768px) {
  .choice-button {
    padding: 0.08rem 0.25rem;
    font-size: var(--composer-choice-font, 1rem);
    margin-right: 0.25rem;
    margin-bottom: 0.15rem;
  }

  .choice-id {
    font-size: var(--composer-choice-font, 1rem);
  }

  .planning-block-choices {
    padding: 0.15rem;
  }
}

/* ====================================================================== */
/* Live choices in the composer — Option C: seamless dock                 */
/* #composer-stack wraps #composer-choices + the #user-input input-group  */
/* inside #interaction-form in ONE bordered surface with hairline         */
/* dividers between rows, so picking a choice and typing free-form text   */
/* visibly belong to the same control. Story history keeps its own        */
/* clickable choices; only the promoted turn's in-story duplicate is      */
/* hidden (see .composer-promoted below).                                 */
/* ====================================================================== */

.composer-choices:empty {
  display: none;
}

/* Collapsed (no live choices this turn): no border, no background — the
   input-group underneath falls back to its normal Bootstrap look, byte-for-
   byte what shipped before this feature existed. */
.composer-row {
  margin-bottom: 0.35rem;
}

.composer-row > .composer-stack {
  margin-bottom: 0;
}

/* E1a action bar (rev-f9kno.5, supersedes C4's Send-only full-width-below-
   dock row from rev-f9kno.1): Send now lives with the avatar + mode toggles
   in one bar, separate from the auto-submit numbered choices above -- see
   the HTML comment above #composer-avatar-slot in index.html for the full
   rationale. Segmented-pill toggle CSS below matches the confirmed E1a mock
   (Claude Design project 386f01e8, e1-variations.html), adapted to real
   radio inputs via Bootstrap's own .btn-check pattern instead of the mock's
   plain <button> toggles. */
.action-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 0.35rem;
}

.toggle-group {
  display: inline-flex;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border-color, rgba(168, 85, 247, 0.25));
  border-radius: 8px;
  padding: 2px;
  gap: 2px;
}

.toggle-group .toggle-pill {
  padding: 5px 9px;
  border: none;
  background: transparent;
  color: var(--text-muted, #8a86a8);
  font-size: 11px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  margin: 0;
}

.toggle-group .btn-check:checked + .toggle-pill {
  background: rgba(168, 85, 247, 0.3);
  color: var(--text-primary, #f0ecff);
  font-weight: 600;
}

.toggle-group .btn-check:focus-visible + .toggle-pill {
  outline: 2px solid rgba(155, 89, 255, 0.55);
  outline-offset: 1px;
}

.composer-send {
  flex: 0 0 auto;
  margin-left: auto;
  height: 34px;
  padding: 8px 20px;
  font-size: var(--composer-choice-font, 1rem);
}

.composer-stack {
  display: block;
  margin-bottom: 0.35rem;
}

/* Docked (choices present): ONE bordered surface around choices + textarea.
   Uses --border-color (not --accent-color): the approved Claude Design mock
   ("Real WorldAI fantasy-theme tokens, lifted from themes/fantasy.css") used
   rgba(168,85,247,.35) for this outer border -- the theme file's own comment
   is explicit: "Gold for text/links. Purple for borders, glows, button bg." */
.composer-stack.composer-stack--has-choices {
  border: 1px solid var(--border-color, #dee2e6);
  border-radius: 6px;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.015);
}

.composer-choices {
  display: block;
  /* Drives the 1/2/3 badges below. A CSS counter (not markup) so the rendered
     DOM and the buttons' accessible names stay byte-identical to the unmoved
     history rendering — the numbering is presentation, exactly as in the mock. */
  counter-reset: composer-choice;
  max-height: 240px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.composer-choices.is-collapsed {
  display: none !important;
}

.composer-choices.is-mode-hidden {
  display: none !important;
}

.composer-choices:empty {
  display: none;
}

/* --- R2a Scroll-Gated Choices Peek Strip --- */
/* The "?" affordance beside each mode pill. Deliberately small and low-contrast
   so it reads as secondary to the pill itself, and deliberately a SEPARATE hit
   target so hovering or tapping a mode never summons a tooltip over the choice
   rows below it (rev-f9kno.15, Slack 2026-08-18). */
.toggle-group .toggle-help {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  padding: 0 0.25rem;
  background: transparent;
  border: 0;
  color: var(--text-muted, #8a86a8);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
}

.toggle-group .toggle-help:hover,
.toggle-group .toggle-help:focus-visible {
  color: var(--text-primary, #f0ecff);
}

.composer-peek-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: linear-gradient(90deg, rgba(168, 85, 247, 0.15) 0%, rgba(139, 92, 246, 0.22) 100%);
  border: 0;
  border-bottom: 1px solid var(--border-color, rgba(168, 85, 247, 0.25));
  padding: 0.45rem 0.75rem;
  color: #e9d5ff;
  font-size: var(--composer-choice-font, 1rem);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.composer-peek-strip:hover {
  background: linear-gradient(90deg, rgba(168, 85, 247, 0.25) 0%, rgba(139, 92, 246, 0.32) 100%);
  color: #ffffff;
}

.composer-peek-strip .peek-indicator {
  font-size: var(--composer-choice-font, 1rem);
  color: #d8b4fe;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Deliberately NO card, border, background or radius per row here — the
   hairline dividers below are the ONLY separators, so the choices and the
   textarea read as rows of the same surface rather than a pile of cards. */
.composer-choices .planning-block-choices {
  margin-bottom: 0 !important;
  padding: 0;
}

.composer-choices .choice-button {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  counter-increment: composer-choice;
  width: 100%;
  margin: 0;
  padding: 9px 6px 9px 12px;
  font-size: var(--composer-choice-font, 1rem);
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: #e2d9f3;
  line-height: 1.4;
  box-shadow: none;
  transition: background 0.12s ease;
  cursor: pointer;
  white-space: normal;
}

.composer-choices .choice-row .choice-select {
  width: auto;
  flex: 1;
  min-width: 0;
}

/* Numbered badge in a fixed left gutter. The textarea's pencil marker sits in
   this SAME column (see #user-input below) — that shared gutter is the whole
   mechanism of C1: "the input keeps the same left gutter as the choice rows,
   but its marker is a pencil instead of a number — so it reads as the final
   item in the same list." Presentational only: aria-hidden by virtue of being
   generated content, so the button's accessible name is still the choice text. */
.composer-choices .choice-button::before {
  content: counter(composer-choice);
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.05rem;
  border-radius: 3px;
  background: rgba(168, 85, 247, 0.2);
  color: #d8b4fe;
  font-size: 0.66rem;
  line-height: 1.125rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Hairline divider ABOVE every row except the first — the top of the dock
   (the first choice) needs none, it already has the outer border. Targets
   .choice-row (not .choice-button/.choice-select), which is now the actual
   row element -- .choice-select is always :first-child of its OWN parent
   (.choice-head) once nested, so the old .choice-button-scoped selector
   would silently stop matching rows 2+. */
.composer-choices .choice-row:not(:first-child) {
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.composer-choices .choice-button:hover {
  background: rgba(255, 255, 255, 0.06);
}

.composer-choices .choice-button:active {
  background: rgba(255, 255, 255, 0.1);
}

.composer-choices .choice-button:focus-visible {
  outline: 2px solid rgba(155, 89, 255, 0.55);
  outline-offset: -2px;
}

.composer-choices .choice-button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* The seam between the LAST choice row and the textarea below: the same
   hairline divider, plus the input-group loses its own top border/radius so
   there is no visible double border where the two surfaces meet. */
.composer-stack--has-choices .composer-stack__input-group {
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.composer-stack--has-choices .composer-stack__input-group #user-input {
  border-top: 0;
  border-left: 0;
  border-right: 0;
  border-radius: 0;
}

/* C1: the textarea itself IS the free-form / custom-action option whenever
   choices are docked — there is no separate custom-action button inside the
   composer (parsePlanningBlocksJson skips it for interactiveOnly; see
   app.js). Its marker is a pencil badge occupying the SAME left gutter column
   as the numbered choice badges above, so the textarea reads as the last item
   in that list rather than a detached field — the mock's stated mechanism.
   The badge is purple-tinted matching the numbered badges above.

   Both the badge box and the glyph are backgrounds on #user-input itself,
   never DOM siblings — so they cannot disturb Bootstrap's first/last-child
   border-radius rules on the input group. (The avatar is no longer an
   input-group child at all: it mounts in #composer-avatar-slot outside the
   dock — see avatar.css.) Offsets are anchored to the TOP, not centered, so
   the badge stays on the first line if the textarea grows.  */
/* The composer's placeholder is the ONLY thing naming the free-form option, so
   it has to be readable. Bootstrap's default `.form-control::placeholder` is
   rgba(33,37,41,.75) — a LIGHT-theme dark grey — and nothing in the dark theme
   overrides it for #user-input (themes/fantasy.css only covers .campaign-wizard
   and .search-box). Composited on this surface that measures 1.05:1, i.e.
   invisible: the placeholder text has never actually been legible here, for
   either "What do you do?" or the custom-action wording. Set explicitly, scoped
   to the game input, so the label the operator asked for is something a player
   can actually read. */
#user-input::placeholder {
  color: rgba(226, 217, 243, 0.72);
  opacity: 1; /* Firefox lowers placeholder opacity by default */
}

.composer-stack--has-choices #user-input::placeholder {
  color: rgba(233, 213, 255, 0.82);
}

.composer-stack--has-choices #user-input {
  font-size: var(--composer-choice-font, 1rem);
  padding-left: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d8b4fe' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4Z'/%3E%3C/svg%3E"),
    linear-gradient(rgba(168, 85, 247, 0.2), rgba(168, 85, 247, 0.2));
  background-repeat: no-repeat, no-repeat;
  background-position:
    0.95rem 0.72rem,
    0.75rem 0.55rem;
  background-size:
    0.7rem 0.7rem,
    1.125rem 1.125rem;
}

/* The turn currently mirrored by the composer hides its in-story duplicate. Every
   other turn keeps its choices visible and clickable in place, so the player can go
   back and pick from an older planning block. */
.story-entry.composer-promoted .planning-block-choices {
  display: none;
}

/* ====================================================================== */
/* Mobile composer: cap choices height                                    */
/*                                                                        */
/* Send-below-dock + full-width is now the default at every viewport (see */
/* the C4 .composer-row/.composer-send rules above) -- PR #8952 originally */
/* shipped that pattern gated to <=576px only; it no longer needs a       */
/* viewport-conditional override here. Phones still need their own       */
/* choices height cap: the dock is too tall to leave room for the rest of */
/* the page when a 4-option planning block is live.                       */
/* ====================================================================== */

@media (max-width: 576px) {
  .composer-row {
    gap: 0.375rem;
  }

  /* Cap choices so 4-option blocks don't dominate the mobile viewport.
     The cap MUST ship with a visible affordance. Measured at 375px, a live
     4-option Quick Start block is 234px tall, so a silent 140px clip hid HALF
     the options — and the clip landed exactly on a row divider, so no partial
     row peeked through to hint more existed. A player then reads
     "1, 2, Custom Action" as the complete list, which is a worse failure than
     the tall dock this cap was added to fix. 148px puts the clip mid-row, and
     the sized scrollbar below is the explicit cue. Keep them together. */
  .composer-choices {
    max-height: 148px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: rgba(168, 85, 247, 0.55) transparent;
  }

  /* WebKit/iOS overlay scrollbars are invisible at rest, so they cue nothing.
     An explicit width forces the bar to render exactly when the list overflows
     and never otherwise — a self-hiding "more below" cue, not permanent chrome. */
  .composer-choices::-webkit-scrollbar {
    width: 4px;
  }

  .composer-choices::-webkit-scrollbar-thumb {
    background: rgba(168, 85, 247, 0.55);
    border-radius: 2px;
  }

  .composer-choices::-webkit-scrollbar-track {
    background: transparent;
  }

  .composer-choices .choice-button {
    padding: 0.45rem 0.6rem;
    /* No font-size here on purpose (rev-f9kno.7). This used to force 0.8125rem
       (13px) to shrink the row below the old 16px base; now the base IS
       12.8px, so the override made mobile LARGER than desktop and broke
       parity with .choice-detail. Inherit the shared token instead. */
    gap: 0.5rem;
  }

  /* Shrinking the rows above moves the badge gutter, so the textarea's pencil
     marker MUST move with it. That shared gutter IS the approved C1 mechanism
     ("its marker is a pencil instead of a number — so it reads as the final
     item in the same list"); leaving these at desktop values silently shipped
     the pre-C1 design on phones (measured: badge 22.6px vs pencil 25px, choice
     text 48.6px vs textarea text 53px). Derived from the same numbers as the
     rows: gutter = 0.6 + 1.125 + 0.5 = 2.225rem; the glyph centres in the badge
     box at 0.6 + (1.125 - 0.7) / 2 ≈ 0.8125rem. The font-size match also stops
     the placeholder truncating mid-word — it is the only thing naming the
     free-form option, so losing half of it defeats the purpose. */
  .composer-stack--has-choices #user-input {
    padding-left: 2.225rem;
    /* 16px is a HARD platform floor here, not a style choice. iOS Safari
       auto-zooms the viewport whenever a focused input's font-size is under
       16px, and it does not zoom back out — so tapping Custom Action zoomed
       the page in, and the reader then had to pinch out to read the next
       narration (operator report, Slack 2026-08-18). Historically the R1
       type scale (--composer-choice-font: 12.8px) is what dropped it under
       the floor. Consume the token so the type-scale contract holds, and
       wrap with max(16px, ...) so a future token drop cannot re-break iOS
       zoom. */
    font-size: max(16px, var(--composer-choice-font, 1rem));
    background-position:
      0.8125rem 0.9rem,
      0.6rem 0.72rem;
  }
}


