/* Webtoon-style comic strip for Claude Code conversations */

/* Lotus Opening palette — Graceful.Dev brand colors.
   See notes/graceful-dev-design.md. */
:root {
  --dancing-red: #A6142f;
  --deep-navy: #0D1940;
  --grace-blue: #3772A6;
  --faith-yellow: #F2CE1B;
  --joy-orange: #F28444;

  --font-title: 'Tenor Sans', Georgia, serif;
  --font-body: 'Sen', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'Cascadia Code', 'Courier New', monospace;
  --font-dialogue: 'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', cursive, sans-serif;
}

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

body {
  background: #fff;
  color: var(--deep-navy);
  font-family: var(--font-body);
  min-height: 100vh;
  /* Allow transitions to/from intrinsic sizes (auto, min-content) so
     <details> content can animate its block-size on expand/collapse. */
  interpolate-size: allow-keywords;
}

.comic-strip {
  max-width: 1600px;
  margin: 0 auto;
  padding: 20px 40px;
  display: flex;
  flex-direction: column;
}

/* Title */
.comic-title {
  text-align: center;
  padding: 30px 20px;
  background: #fff;
  border: 3px solid var(--dancing-red);
  border-radius: 16px;
  margin-bottom: 12px;
}

.comic-title h1 {
  font-family: var(--font-title);
  font-size: 1.8rem;
  color: var(--dancing-red);
  text-transform: uppercase;
  letter-spacing: 2px;
}

.toggle-bar {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 12px;
}

.toggle-btn {
  background: #fff;
  border: 1px solid var(--grace-blue);
  color: var(--grace-blue);
  padding: 6px 14px;
  border-radius: 6px;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: bold;
  cursor: pointer;
}

.toggle-btn:hover {
  background: #eaf1f7;
  color: var(--deep-navy);
}

.toggle-btn kbd {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 5px;
  border: 1px solid var(--grace-blue);
  border-radius: 3px;
  background: #f4f7fa;
  font-family: inherit;
  font-size: 0.75rem;
  color: var(--deep-navy);
}

/* Panels — the basic building block */
.panel {
  padding: 8px 20px;
  border-radius: 12px;
  position: relative;
}

/* Panel reveal: hidden top-level panels keep their layout footprint so
   the full length of the comic is visible, but their contents don't
   render. Arrow keys walk forward/back through the reveal sequence.
   Panel-hidden is only applied to the reveal system's top-level panels
   (including those inside a .robot-sequence), never to subagent
   subpanels deeper in the tree. */
.panel.panel-hidden {
  visibility: hidden;
}

/* Entrance transitions. Think bubbles fade in on reveal.
   The asymmetric visibility transition (0s on reveal, delayed on hide)
   keeps the element painted while it fades out, then snaps it hidden
   once opacity has reached 0. */
.claude-think {
  transition: opacity 400ms ease, visibility 0s linear 0s;
}
.claude-think.panel-hidden {
  opacity: 0;
  transition: opacity 400ms ease, visibility 0s linear 400ms;
}

/* Notifications slide in from the right — "a messenger arrived mid-flow".
   If the notification knows which tool_use spawned its background task,
   JS sets --origin-dx / --origin-dy to the delta from that element's
   on-screen position, so the panel flies in from the originating
   action-montage. Otherwise the defaults below act as a plain "arrive
   from the right" fallback. */
.notification {
  --origin-dx: 80px;
  --origin-dy: 0px;
  /* Incoming: fade in fast (first ~150ms) so the box is visible near its
     origin point while it's still sliding. The transform takes longer so
     the reader can watch the arc. */
  transition:
    transform 500ms cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 150ms ease-out,
    visibility 0s linear 0s;
}
.notification.panel-hidden {
  transform: translate(var(--origin-dx), var(--origin-dy));
  opacity: 0;
  /* Outgoing: slide and fade together so it retreats cleanly to the origin. */
  transition:
    transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 320ms ease-out,
    visibility 0s linear 320ms;
}

/* Two-phase intermediate: notification is fully visible but still parked
   at its originating action's position. The next arrow press removes
   this class, and the base .notification transition slides it home. */
.notification.notification-at-origin {
  transform: translate(var(--origin-dx), var(--origin-dy));
  opacity: 1;
}

/* Hovering a notification traces it back to the action that spawned it. */
.notification[data-origin-tool-use-id] {
  cursor: help;
}
.notification.is-hovering-origin .notification-box {
  box-shadow: 0 0 0 2px var(--dancing-red);
}
.action-montage.highlight-origin,
li[data-tool-use-id].highlight-origin {
  outline: 2px solid var(--dancing-red);
  outline-offset: 2px;
  background-color: rgba(166, 20, 47, 0.08);
  border-radius: 4px;
  transition: outline-color 120ms ease, background-color 120ms ease;
}

/* Source tag — hidden unless body.show-refs is set (debug mode toggle) */
.source-tag {
  position: absolute;
  top: -8px;
  right: 8px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: bold;
  color: #fff;
  background: #534b8a;
  padding: 1px 6px;
  border-radius: 3px;
  z-index: 10;
  cursor: pointer;
  user-select: none;
  text-decoration: none;
  display: none;
}

body.show-refs .source-tag {
  display: inline-block;
}

.source-tag:hover {
  background: var(--dancing-red);
}

.source-tag.copied {
  background: #4a8a4a;
}

/* Token badge — total input tokens sent on this turn. Hidden unless body.show-tokens is set.
   Positioned absolutely to the LEFT of the panel so that when tokens are toggled on
   they don't reshape the layout — they just appear in the left margin / overlap
   whatever is there. This means no whitespace needs to be reserved for them. */
.token-badge {
  position: absolute;
  top: 4px;
  right: 100%;
  margin-right: 6px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: bold;
  color: var(--deep-navy);
  background: var(--faith-yellow);
  padding: 1px 6px;
  border-radius: 3px;
  z-index: 10;
  user-select: none;
  white-space: nowrap;
  display: none;
}

body.show-tokens .token-badge {
  display: inline-block;
}

/* In the action-montage expansion, tokens show inline next to each tool name. */
.montage-details .token-badge {
  position: static;
  margin-left: 6px;
  margin-right: 0;
}

/* === Human speech === */
.human-speech {
  align-self: flex-start;
  max-width: 55%;
}

/* Content-sized like the Claude bubble, anchored to the left edge of
   its panel so it grows rightward as the text types in. */
.human-speech .speech-bubble {
  width: fit-content;
  max-width: 100%;
}

.character-avatar {
  width: auto;
  display: block;
}

/* Avatar is taken out of flow so the human's picture doesn't push
   subsequent (right-side) Claude panels downward. It hangs below
   the bubble into whatever empty space is next on the left. */
.human-avatar {
  position: absolute;
  top: 100%;
  left: 26px;
  height: 90px;
}

.character-label {
  font-size: 0.75rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 4px;
  padding-left: 12px;
  opacity: 0.7;
}

.speech-bubble {
  padding: 14px 18px;
  border-radius: 18px;
  position: relative;
  line-height: 1.5;
  font-family: var(--font-dialogue);
}

.human-bubble {
  background: #fff;
  border: 2px solid var(--grace-blue);
  color: var(--deep-navy);
}

.human-bubble::after {
  content: '';
  position: absolute;
  bottom: -12px;
  left: 28px;
  border: 6px solid transparent;
  border-top-color: var(--grace-blue);
}

/* === Robot sequence ===
   Wraps contiguous claude-think / action-montage / spawn-agent /
   claude-speech panels so a single robot graphic can move through them
   as they reveal. The wrapper spans the full comic-strip width; each
   panel inside keeps its own horizontal zone (backstage-right for
   think/action, dialogue-center for speech). The robot is absolutely
   positioned inside the sequence and JS sets its transform to land
   just-left-of whichever panel is currently the last revealed. */
.robot-sequence {
  align-self: stretch;
  width: 100%;
  position: relative;
}

.sequence-panels {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Panels inside the sequence all sit to the right of the fixed robot
   column. Speech is closer to the robot (smaller gap, more intimate
   dialogue feel); think/action have a bigger gap (backstage, further
   from the speaker). Widths are picked so all three fit to the right of
   the robot without overlapping it. */
.sequence-panels > .claude-think,
.sequence-panels > .action-montage,
.sequence-panels > .spawn-agent {
  align-self: flex-end;
  width: 50%;
  max-width: none;
  margin-right: 0;
}

.sequence-panels > .claude-speech {
  align-self: flex-end;
  width: 55%;
  max-width: none;
  margin-right: 18%;
}

.sequence-robot {
  position: absolute;
  top: 0;
  /* The robot's column. Its right edge sits at ~26% of the content
     width; speech starts at 27% (tight gap), think/action at 50%
     (bigger gap). Robot only moves vertically — translateY tracks the
     current panel's offsetTop. */
  left: 22%;
  height: 90px;
  width: auto;
  transition: transform 500ms ease;
  /* Hidden until at least one panel in the sequence is visible. */
  visibility: hidden;
}

.robot-sequence:has(> .sequence-panels > .panel:not(.panel-hidden)) > .sequence-robot {
  visibility: visible;
}

/* === Claude speech === */
.claude-speech .speech-bubble {
  /* Content-sized so the bubble's right edge extends as text is typed
     in. min-width: 0 lets it shrink to wrap text rather than overflow. */
  min-width: 0;
  max-width: 100%;
  width: fit-content;
}

.claude-bubble {
  background: #fff;
  border: 2px solid var(--dancing-red);
  color: var(--deep-navy);
}

.claude-bubble::after {
  content: '';
  position: absolute;
  top: 14px;
  left: -12px;
  border: 6px solid transparent;
  border-right-color: var(--dancing-red);
}

.speech-bubble p {
  margin-bottom: 8px;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.speech-bubble p:last-child {
  margin-bottom: 0;
}

/* === Thinking === */
.claude-think {
  align-self: flex-end;
  width: 55%;
  z-index: 2;
  position: relative;
}

.thought-bubble {
  background: #eaf1f7;
  border: 2px dotted var(--grace-blue);
  border-radius: 18px;
  padding: 12px 18px;
  color: var(--deep-navy);
  font-family: var(--font-body);
  font-style: italic;
  font-size: 0.9rem;
  line-height: 1.4;
  position: relative;
}

.thought-bubble::before {
  content: '💭';
  position: absolute;
  bottom: -14px;
  left: 16px;
  font-size: 1.2rem;
}

.thought-bubble p {
  margin-bottom: 6px;
}

.thought-bubble p:last-child {
  margin-bottom: 0;
}

/* === Action Montage === */
.action-montage {
  align-self: flex-end;
  width: 55%;
  z-index: 0;
  position: relative;
}

/* Leave a little room between a thought and the action that follows it:
   the 💭 tail hangs 14px below the bubble and the "⚡ ACTION ⚡" banner
   sits 12px above the burst. Enough margin to avoid a bad collision,
   not so much that the panels feel disconnected. */
.claude-think + .action-montage {
  margin-top: 6px;
  z-index: 0;
}

.subagent-comic .claude-think + .action-montage {
  margin-top: 8px;
}

.montage-burst {
  background: linear-gradient(135deg, #fff 0%, #fff7e6 50%, #fde9d6 100%);
  border: 3px solid var(--dancing-red);
  border-radius: 8px;
  padding: 20px 16px 12px 16px;
  position: relative;
}

/* Animate the details contents on expand/collapse. Relies on
   interpolate-size on body for block-size: auto transitions, and
   transition-behavior: allow-discrete to tween content-visibility. */
.montage-burst::details-content {
  block-size: 0;
  opacity: 0;
  overflow: clip;
  transition:
    block-size 250ms ease,
    opacity 200ms ease,
    content-visibility 250ms allow-discrete;
}

.montage-burst[open]::details-content {
  block-size: auto;
  opacity: 1;
}

.montage-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-body);
  font-weight: bold;
  font-size: 0.9rem;
  color: var(--dancing-red);
}

.montage-summary::-webkit-details-marker {
  display: none;
}

.montage-burst::before {
  content: '⚡ ACTION ⚡';
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--dancing-red);
  color: #fff;
  font-size: 0.7rem;
  font-weight: bold;
  letter-spacing: 2px;
  padding: 2px 12px;
  border-radius: 4px;
}

.montage-details {
  list-style: none;
  padding: 8px 0 0 0;
  margin: 8px 0 0 0;
  border-top: 1px solid var(--grace-blue);
}

.montage-details li {
  padding: 3px 0;
  font-size: 0.8rem;
  color: var(--deep-navy);
  font-family: var(--font-mono);
}

.montage-details strong {
  color: var(--grace-blue);
}

/* Batch grouping: tools emitted in one assistant message = one batch.
   First batch keeps the border-top that separates it from the summary;
   subsequent batches are separated by the round-trip divider. */
.montage-batches {
  padding-top: 8px;
  border-top: 1px solid var(--grace-blue);
  margin-top: 8px;
}

.montage-batches .montage-details {
  border-top: none;
  padding-top: 0;
  margin-top: 0;
}

.montage-batch {
  position: relative;
}

.batch-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.7rem;
  font-family: var(--font-body);
  color: var(--grace-blue);
  margin-bottom: 2px;
}

.batch-parallel {
  display: inline-block;
  background: var(--grace-blue);
  color: #fff;
  padding: 1px 6px;
  border-radius: 3px;
  font-weight: bold;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  font-size: 0.65rem;
}

/* Round-trip divider: Claude saw the previous tool's result, then called
   again. Shown between sequential batches within one montage, or at the top
   of a montage whose first batch "owns" its API call's tokens. Carries the
   new turn's token badge when that batch has no thought/speech panel above. */
.montage-roundtrip {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px 0;
  position: relative;
  gap: 6px;
}

.montage-roundtrip::before,
.montage-roundtrip::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--dancing-red);
  opacity: 0.3;
}

.roundtrip-arrow {
  color: var(--dancing-red);
  font-size: 1.1rem;
  font-weight: bold;
}

/* Token badge on a round-trip marker: inline (not floated to the margin
   like the default token-badge), but still gated by body.show-tokens so
   the user decides when to see the numbers. */
.montage-roundtrip .token-badge {
  position: static;
  margin: 0;
}

body.show-tokens .montage-roundtrip .token-badge {
  display: inline-block;
}

.tool-command {
  display: block;
  color: #3b7a5a;
  margin-top: 2px;
  padding-left: 8px;
}

/* === Spawn Agent panel — for Agent tool calls that spawn a subagent.
   Collapsed: matches an action-montage (55% right-aligned) so it tucks into
   the normal right-hand column. Expanded: widens leftward to the Claude
   bubble's left edge, giving the nested comic room to breathe. Alignment math
   (expanded):
     claude-speech container left = 100% − 30% (margin-right) − 55% (max-width) = 15%
     inside, the robot (~66px wide at 90px tall, aspect 181/246) + 10px gap
     inset the bubble another ~76px. */
.spawn-agent {
  align-self: flex-end;
  width: 55%;
  margin-right: 0;
  transition: width 260ms ease;
}

.spawn-agent:has(.spawn-agent-burst[open]) {
  width: calc(85% - 76px);
}

.spawn-agent-burst {
  background: linear-gradient(135deg, #fff 0%, #fde9d6 100%);
  border: 3px solid var(--joy-orange);
  border-radius: 8px;
  padding: 20px 16px 12px 16px;
  position: relative;
}

.spawn-agent-burst::before {
  content: '⊹ SPAWN AGENT ⊹';
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--joy-orange);
  color: #fff;
  font-size: 0.7rem;
  font-weight: bold;
  letter-spacing: 2px;
  padding: 2px 12px;
  border-radius: 4px;
}

.spawn-agent-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: center;
  align-items: baseline;
  cursor: pointer;
  list-style: none;
  padding-top: 8px;
  font-family: var(--font-body);
}

.spawn-agent-summary::-webkit-details-marker {
  display: none;
}

.spawn-agent-type {
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: bold;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: #fff;
  background: var(--joy-orange);
  padding: 2px 8px;
  border-radius: 3px;
}

.spawn-agent-title {
  font-weight: bold;
  font-size: 1rem;
  color: var(--dancing-red);
}

.spawn-agent-count {
  font-size: 0.85rem;
  color: var(--grace-blue);
}

.spawn-agent .subagent-comic {
  margin-top: 12px;
  border-top: 1px solid var(--joy-orange);
  border-left: none;
  border-radius: 0;
  padding: 12px 0 0 0;
  background: transparent;
}

/* === Subagent nested comic === */
.subagent-details {
  margin-top: 6px;
}

.subagent-toggle {
  cursor: pointer;
  color: var(--joy-orange);
  font-size: 0.85rem;
  font-weight: bold;
  padding: 2px 8px;
  border: 1px solid var(--joy-orange);
  border-radius: 4px;
  display: inline-block;
}

.subagent-toggle:hover {
  background: #fdeee0;
  color: var(--dancing-red);
}

.subagent-comic {
  margin-top: 8px;
  padding: 10px;
  border-left: 3px solid var(--joy-orange);
  background: rgba(242, 132, 68, 0.08);
  border-radius: 0 8px 8px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.subagent-comic .panel {
  font-size: 0.9em;
}

/* Inside a subagent, let the right-side robot bubble reach all the way to
   the right edge — same as the action panels — by dropping the outer 30%
   margin. Cap max-width at 85% so the LEFT edge stays around the 15% mark,
   leaving the left column for the other robot picture. */
.subagent-comic .claude-speech {
  margin-right: 0;
  max-width: 85%;
}

/* Inside a subagent, the "user" is really the parent Claude
   giving instructions — so render the robot image there too. */
.subagent-comic .human-avatar {
  content: url("robot.png");
}

/* Shrink avatars inside the nested subagent comic. */
.subagent-comic .character-avatar {
  height: 60px;
}


.subagent-comic .montage-burst {
  border-width: 2px;
}

.subagent-comic .montage-burst::before {
  font-size: 0.6rem;
  padding: 1px 8px;
}

.tool-output-details {
  margin-top: 4px;
  position: relative;
}

.tool-output-toggle {
  cursor: pointer;
  color: var(--grace-blue);
  font-weight: bold;
  font-family: var(--font-mono);
  list-style: none;
}

.tool-output-toggle::-webkit-details-marker {
  display: none;
}

/* Open: overlay a small [−] button in the upper-right of the output pre. */
.tool-output-details[open] > .tool-output-toggle {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  font-size: 0.85rem;
  line-height: 1;
  padding: 2px 6px;
  border: 1px solid var(--grace-blue);
  border-radius: 4px;
  background: #fff;
}

.tool-output-details[open] > .tool-output-toggle::before {
  content: "[−]";
}

/* Closed: inline "[+] output" pill. */
.tool-output-details:not([open]) > .tool-output-toggle {
  display: inline-block;
  font-size: 0.85rem;
  padding: 2px 8px;
  border: 1px solid var(--grace-blue);
  border-radius: 4px;
  margin-top: 4px;
}

.tool-output-details:not([open]) > .tool-output-toggle::before {
  content: "[+] output";
}

.tool-output-toggle:hover {
  background: #eaf1f7;
  color: var(--deep-navy);
}

.tool-output {
  background: #f6f8fa;
  border: 1px solid var(--grace-blue);
  border-radius: 4px;
  padding: 12px;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--deep-navy);
  margin-top: 6px;
  overflow-x: auto;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* === Notification (background task reporting in) === */
.notification {
  align-self: flex-end;
  max-width: 50%;
  margin-right: 30%;
}

.notification-box {
  background: #eaf5ea;
  border: 1px solid #4a8a4a;
  border-radius: 8px;
  padding: 8px 14px;
  color: #2e5e2e;
  font-size: 0.8rem;
  font-family: var(--font-mono);
  position: relative;
}

.notification-box::before {
  content: '📬';
  position: absolute;
  bottom: -12px;
  left: 12px;
  font-size: 1rem;
}

.notification-box p {
  margin: 0;
}

/* === Narrator === */
.narrator {
  align-self: center;
  max-width: 90%;
}

.narrator-box {
  background: #f7ecf2;
  border: 1px solid #843b62;
  border-radius: 4px;
  padding: 10px 16px;
  color: #5a2845;
  font-style: italic;
  font-size: 0.85rem;
  text-align: center;
}

.narrator-box p {
  margin-bottom: 4px;
}

.narrator-box p:last-child {
  margin-bottom: 0;
}

/* End marker */
.comic-end {
  text-align: center;
  padding: 30px;
  font-family: var(--font-title);
  font-size: 1.4rem;
  color: #7a6fa8;
  font-style: italic;
  letter-spacing: 2px;
}

.conversation-totals {
  margin-top: 4px;
  padding: 16px 24px;
  background: #fff;
  border: 2px solid var(--grace-blue);
  border-radius: 12px;
  text-align: center;
  font-family: var(--font-body);
  color: var(--deep-navy);
}

.conversation-totals .totals-label {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--grace-blue);
  margin-bottom: 6px;
}

.conversation-totals .totals-numbers {
  font-family: var(--font-mono);
  font-size: 1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  align-items: baseline;
}

.conversation-totals .totals-bucket strong {
  color: var(--dancing-red);
  font-size: 1.15rem;
}

.conversation-totals .totals-sep {
  color: var(--grace-blue);
  opacity: 0.5;
}

/* Queued panels — human typed while Claude was busy. Hidden by default
   because the same text re-appears as a regular user record at the
   dequeued position (where Claude actually received it). Revealed with
   the 'q' toggle; the dashed border marks "Claude wasn't looking yet". */
.panel.queued {
  display: none;
}

body.show-queued .panel.queued {
  display: block;
}

body.show-queued .panel.queued .speech-bubble,
body.show-queued .panel.queued .notification-box {
  border-style: dashed;
  border-width: 2px;
}
