/* Agent runs, laid out: the run page (agent_runs/show — its sidebar and the
   streaming transcript of Messages), the live view (agent_runs/live — a Card
   per run in flight, an Item per run finished) and the inspector Sheet a
   card opens (agent_runs/inspections/show).

   Much of what streams in arrives as bare text appended to an element
   (Message#broadcast_append_chunk, Chat#broadcast_status), so what is shown
   and hidden is decided here by whether those elements are :empty — the
   markup writes them with nothing between their tags. Every piece is the
   kit's, so this file only places them and shows or hides them. */
@layer ui {
  /* A placeholder of the kit's Skeleton lines (agent_runs/_skeleton), in a
     fixed cycle of widths, so a re-render doesn't reshuffle them while
     someone is looking. */
  .skeleton {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }

  .skeleton__line {
    block-size: 0.75rem;
    inline-size: 92%;

    &:nth-child(5n + 2) { inline-size: 70%; }
    &:nth-child(5n + 3) { inline-size: 84%; }
    &:nth-child(5n + 4) { inline-size: 60%; }
    &:nth-child(5n + 5) { inline-size: 78%; }
  }

  /* ---- The run page ---- */

  /* The sidebar (agent_runs/_panel): a run's error can be a long provider
     message with no spaces to break at. */
  .run-panel__error {
    overflow-wrap: anywhere;
  }

  /* The proposals table, edge to edge in its box: its outer cells keep off
     the box's edge, and its caption off the box's foot. */
  .run-panel__proposals {
    :is(th, td):first-child { padding-inline-start: 1rem; }
    :is(th, td):last-child { padding-inline-end: 1rem; }

    caption {
      margin-block-start: 0.5rem;
      padding: 0 1rem 0.75rem;
    }
  }

  /* The transcript card's body: the log, then the status line under it. */
  .transcript {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }

  .transcript__log {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-block-size: 60vh;
    overflow-y: auto;
  }

  .transcript__messages {
    display: flex;
    flex-direction: column;
  }

  /* The skeleton goes once a turn has words in it, or once the panel says
     the run is over. */
  .transcript__log:has(.chat-bubble__text:not(:empty), .chat-bubble .prose, .chat-bubble__thinking-text:not(:empty)) .transcript__skeleton,
  .agent-run:has(.run-panel[data-running="false"]) .transcript__skeleton {
    display: none;
  }

  .transcript__status {
    align-items: center;
    display: flex;
    gap: 0.5rem;

    &:has(.transcript__status-label:empty) {
      display: none;
    }
  }

  /* One turn (a ui-message). One with nothing to show yet — the shell a
     reply streams into — isn't shown. */
  .chat-bubble:not(:has(.chat-bubble__text:not(:empty), .prose, .chat-bubble__thinking-text:not(:empty))) {
    display: none;
  }

  .chat-bubble--assistant > .ui-message__content {
    min-inline-size: 0;
  }

  .chat-bubble__text {
    overflow-wrap: anywhere;
    white-space: pre-wrap;

    &:empty {
      display: none;
    }
  }

  /* Its reasoning: a Collapsible, gone while there's none. */
  .chat-bubble__thinking:has(.chat-bubble__thinking-text:empty) {
    display: none;
  }

  .chat-bubble__summary {
    cursor: pointer;
    list-style: none;
    user-select: none;

    &::-webkit-details-marker { display: none; }
  }

  .chat-bubble__thinking-text {
    margin-block-start: 0.25rem;
    white-space: pre-wrap;
  }

  .chat-bubble__image {
    max-block-size: 10rem;
  }

  /* ---- The live view ---- */

  /* "Running now", its icon and its count, over the board. */
  .run-board__heading {
    align-items: center;
    display: flex;
    gap: 0.5rem;
    margin: 0;
  }

  .run-board {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr));
  }

  /* One run in flight, a Card. The agent's name, its title, is stretched
     over the whole card; the badges and the Stop button sit above it. */
  .run-card {
    position: relative;
  }

  .run-card__open::after {
    content: "";
    inset: 0;
    position: absolute;
  }

  .run-card__badges,
  .run-card__actions {
    position: relative;
    z-index: 1;
  }

  .run-card__badges {
    align-items: center;
    flex-wrap: wrap;
  }

  /* The status line while a run works between tools: the line is cleared for
     the reply, and "Working…" stands in. */
  .run-card__status-label:empty::before {
    content: attr(data-fallback);
  }

  .run-card__trail {
    margin: 0;
    padding: 0;
  }

  /* A tool's badge: a long label is cut rather than pushing past the card. */
  .run-card__step {
    max-inline-size: 100%;
  }

  /* The words as they arrive. Both show their latest lines: overflow goes off
     the top, the way a reply being written is read. */
  .run-card__thinking,
  .run-card__preview {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    margin: 0;
    overflow: hidden;
    overflow-wrap: anywhere;
    white-space: pre-wrap;

    &:empty {
      display: none;
    }
  }

  .run-card__thinking {
    max-block-size: 2.5rem;
  }

  .run-card__preview {
    max-block-size: 4rem;
  }

  .run-card__foot {
    flex-wrap: wrap;
  }

  /* Recently finished: an empty one's message clear of the card's edges. */
  .run-recent__empty {
    padding-block: 1.5rem;
  }

  /* A finished run: its figures stay at the Item's end rather than wrapping
     under it. */
  .run-row > .ui-item {
    flex-wrap: nowrap;
  }

  .run-row__figures {
    display: grid;
    flex-shrink: 0;
    justify-items: end;
  }

  /* ---- The inspector ---- */

  /* A wide sheet whose parts run edge to edge: the header, what's happening
     now, the tabs, the scrolling body and the footer, top to bottom. */
  .ui-sheet.run-inspector {
    gap: 0;
    padding: 0;

    &[open] {
      display: flex;
      flex-direction: column;
    }
  }

  .run-inspector__close {
    z-index: 1;
  }

  .run-inspector__frame {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-block-size: 0;

    &[busy] {
      opacity: 0.6;
    }

    /* The skeleton, before a run has been opened. */
    > .skeleton {
      padding: 1.5rem;
    }
  }

  .run-inspector__header {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1.5rem 3rem 1rem 1.5rem;
  }

  /* Tools · Proposals · Tokens · Cost: labels over their figures. */
  .run-inspector__stats {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    margin: 0.5rem 0 0;

    dd {
      margin: 0;
    }
  }

  /* What is happening right now, over the tabs. */
  .ui-alert.run-inspector__now {
    inline-size: auto;
    margin: 0 1.5rem 1rem;
  }

  /* The line tabs across the sheet, in line with its padding. */
  .run-inspector__tabs {
    flex-shrink: 0;
    padding-inline: 1.5rem;
  }

  .run-inspector__body {
    flex: 1;
    min-block-size: 0;
    overflow-y: auto;
    padding: 1rem 1.5rem;
  }

  .run-inspector__foot {
    align-items: center;
    display: flex;
    flex-shrink: 0;
    gap: 0.5rem;
    justify-content: space-between;
    padding: 0.75rem 1.5rem;
  }

  /* The run as it happened: an Item a moment, its icon at the top. */
  .ui-item.run-timeline__event {
    align-items: flex-start;
  }

  .run-timeline__thinking {
    margin: 0;
    white-space: pre-wrap;
  }

  /* Code cut down past a few lines, the rest behind a disclosure. */
  .run-code__block {
    max-block-size: 28rem;
    overflow: auto;
  }

  .run-code:has(.run-code__toggle[open]) .run-code__preview,
  .run-code__toggle[open] .run-code__more,
  .run-code__toggle:not([open]) .run-code__less {
    display: none;
  }

  .run-code__toggle > summary {
    cursor: pointer;
    list-style: none;
    margin-block: 0.25rem;

    &::-webkit-details-marker { display: none; }
  }
}
