/* static/rag/rag-ui.css - NEW FILE (2026-10-05, document upload + RAG,
   phase 6 of 6, batch 6a).

   WHY THIS IS ITS OWN FILE RATHER THAN MORE RULES IN static/index.html.
   index.html is a root file and already carries 270 lines of <style> for the
   chat, the header and the five gate panels. This feature gets its own folder
   beside its own code - the same arrangement rag/, session_stores/redis/ and
   mcp_servers/ have - so that index.html holds only the mount point and the
   two tags that reference this folder. Phase 6b and 6c add to THIS file.

   IT DEFINES NO COLOURS. Every colour below is a token from
   static/brand.css: --bg, --surface, --field, --ink, --muted, --line,
   --code-bg, --error, --note, --accent, --accent-ink, --accent-soft,
   --warn-bg, --warn-ink, --warn-line, --sans, --mono. That is deliberate and
   it is what makes dark mode free: brand.css redefines those tokens under
   `@media (prefers-color-scheme: dark)` and nothing here has to know. A
   hex value in this file would be a second definition of a colour, and the
   second one is the one that goes stale - the same argument brand.css's own
   header makes about index.html's old :root block.

   ONE EXCEPTION, AND IT IS NOT A COLOUR: the drop overlay uses
   `color-mix(in srgb, var(--accent) 12%, transparent)` so the tint follows
   the accent token in both themes instead of being a third green. */

/* ---------------------------------------------------------------------------
   THE PANEL. It lives in the footer, directly above the composer, because his
   design is that the questions are asked IN THE CHAT BOX - not in a modal and
   not in a separate upload screen. An empty panel is display:none so the
   footer keeps its normal height until files actually arrive.
   --------------------------------------------------------------------------- */
#rag-panel {
  display: none;
  margin: 0 0 0.6rem 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  font: 0.8125rem/1.5 var(--sans);
  color: var(--ink);
  overflow: hidden;
}

#rag-panel.rag-open { display: block; }

.rag-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--line);
}

.rag-row:last-child { border-bottom: none; }

.rag-title {
  font-weight: 600;
  color: var(--ink);
}

.rag-muted { color: var(--muted); }

.rag-grow { flex: 1 1 auto; min-width: 0; }

/* ---------------------------------------------------------------------------
   BUTTONS. `button` in index.html already has `font: inherit` and a shared
   look; these only add the two shapes this feature needs.
   --------------------------------------------------------------------------- */
.rag-btn {
  font: inherit;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--field);
  color: var(--ink);
  cursor: pointer;
}

.rag-btn:hover { background: var(--accent-soft); }

.rag-btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.rag-btn-primary:hover { background: var(--accent); opacity: 0.9; }

.rag-btn[disabled] { opacity: 0.55; cursor: default; }
.rag-btn[disabled]:hover { background: var(--field); }

/* The default provider is marked rather than pre-selected: the question is
   still asked, because the provider binds at ingest and is part of the
   collection name forever. A pre-ticked radio invites Enter. */
.rag-default-flag {
  font-size: 0.7rem;
  color: var(--muted);
  margin-left: 0.25rem;
}

/* ---------------------------------------------------------------------------
   THE FILE LIST. One line per file, because a folder drop of twenty in which
   nineteen worked and one was a .zip has to report exactly that - the same
   reason POST /rag/uploads answers per file instead of with one number.
   --------------------------------------------------------------------------- */
.rag-files {
  margin: 0;
  padding: 0.35rem 0.75rem 0.55rem 0.75rem;
  list-style: none;
  max-height: 11rem;
  overflow-y: auto;
}

.rag-file {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.15rem 0;
}

.rag-file-name {
  font-family: var(--mono);
  font-size: 0.75rem;
  overflow-wrap: anywhere;
}

.rag-file-note {
  color: var(--muted);
  font-size: 0.75rem;
}

/* The four outcomes are distinguished by a word AND a colour, never by colour
   alone - `accepted`/`rejected`/`failed` are the API's own words and are
   printed as text so the state survives a screenshot, a colour-blind reader
   and a monochrome print. */
.rag-state {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.rag-state-ok { color: var(--accent); }
.rag-state-bad { color: var(--error); }
.rag-state-warn { color: var(--warn-ink); }
.rag-state-busy { color: var(--note); }

/* ---------------------------------------------------------------------------
   PROGRESS. A determinate bar, because the batch endpoint reports
   documents_in_batch and the per-state counts, so the fraction is known.
   --------------------------------------------------------------------------- */
.rag-bar {
  position: relative;
  height: 4px;
  border-radius: 2px;
  background: var(--code-bg);
  overflow: hidden;
  flex: 1 1 8rem;
}

.rag-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--accent);
  transition: width 180ms linear;
}

/* ---------------------------------------------------------------------------
   NOTICES. Three kinds, and the distinction is the point: a WARNING is the
   server telling the browser something it must pass on (the
   skipped_collections case, where an answer came from some of a session's
   documents and the only sign is a field in the JSON), an ERROR is a request
   that did not work, and a NOTE is this page explaining itself.
   --------------------------------------------------------------------------- */
.rag-warn {
  margin: 0;
  padding: 0.5rem 0.75rem;
  background: var(--warn-bg);
  border-top: 1px solid var(--warn-line);
  color: var(--warn-ink);
  font-size: 0.75rem;
}

.rag-err {
  margin: 0;
  padding: 0.5rem 0.75rem;
  color: var(--error);
  font-size: 0.75rem;
  border-top: 1px solid var(--line);
}

.rag-note {
  margin: 0;
  padding: 0.5rem 0.75rem;
  color: var(--muted);
  font-size: 0.75rem;
  border-top: 1px solid var(--line);
}

/* `error` is shown in a <pre> because it carries the vendor's own body, which
   is where the actionable half of a 429 or a 400 lives. Open item 110 records
   that `reason` is filled with prose on a dry run and says nothing useful on a
   failure, so a reader who checks only `reason` learns nothing exactly when
   something has gone wrong - this page therefore shows BOTH and labels them. */
.rag-detail {
  margin: 0.3rem 0 0 0;
  padding: 0.4rem 0.5rem;
  background: var(--code-bg);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 0.7rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 8rem;
  overflow-y: auto;
}

/* ---------------------------------------------------------------------------
   THE DROP TARGET. The whole footer is the target, so a drop does not have to
   find a small rectangle, and the overlay only appears while a drag that
   actually carries files is over it.
   --------------------------------------------------------------------------- */
footer.rag-dragging {
  outline: 2px dashed var(--accent);
  outline-offset: -4px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* ---------------------------------------------------------------------------
   THE ATTACH BUTTON, in the composer row.
   --------------------------------------------------------------------------- */
#rag-attach {
  font: inherit;
  flex: 0 0 auto;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--field);
  color: var(--ink);
  cursor: pointer;
  line-height: 1;
}

#rag-attach:hover { background: var(--accent-soft); }
#rag-attach[disabled] { opacity: 0.5; cursor: default; }
#rag-attach[disabled]:hover { background: var(--field); }

/* ---------------------------------------------------------------------------
   THE CITATION STRIP, rendered under an assistant reply from the `grounding`
   SSE frame. Before batch 6a the page received that frame and dropped it, so
   whether an answer was grounded at all was visible only in the server log.

   IT REPORTS THE COST AND THE LOSS, not just the passages. `rerank_tokens` is
   what the turn spent, and `dropped_for_budget` counts passages that were
   retrieved, reranked and PAID FOR and then not shown to the model - which is
   the measurement Open item 123 was decided on, and the thing a person
   tuning rag/rag.ini needs to see without reading a log.
   --------------------------------------------------------------------------- */
.rag-cite {
  margin: 0.4rem 0 0 0;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  background: var(--surface);
  font: 0.75rem/1.5 var(--sans);
  color: var(--muted);
}

.rag-cite-ungrounded { border-left-color: var(--muted); }

.rag-cite-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  color: var(--ink);
  font-weight: 600;
}

.rag-cite-cost {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 400;
  color: var(--muted);
}

.rag-cite-list {
  margin: 0.3rem 0 0 0;
  padding: 0;
  list-style: none;
}

.rag-cite-item {
  display: flex;
  gap: 0.4rem;
  align-items: baseline;
  padding: 0.1rem 0;
}

.rag-cite-num {
  font-family: var(--mono);
  font-weight: 600;
  color: var(--accent);
  flex: 0 0 auto;
}

.rag-cite-file {
  font-family: var(--mono);
  font-size: 0.7rem;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.rag-cite-where { color: var(--muted); font-size: 0.7rem; }

.rag-cite-drop {
  margin: 0.35rem 0 0 0;
  padding: 0.35rem 0.5rem;
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  border-radius: 4px;
  color: var(--warn-ink);
  font-size: 0.7rem;
}

.rag-cite-why {
  margin: 0.3rem 0 0 0;
  font-size: 0.7rem;
  color: var(--muted);
}

/* The chip in the composer row that shows, and lets you change, whether the
   next turn is answered from your documents. It is a visible control rather
   than a remembered mode: a hidden toggle that silently spends money on a
   rerank is exactly what [answers] retrieve_on_chat = false exists to avoid. */
#rag-gate {
  display: none;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--muted);
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--field);
}

#rag-gate.rag-open { display: inline-flex; }
#rag-gate strong { color: var(--ink); font-weight: 600; }

.rag-gate-on { border-color: var(--accent); }

@media (max-width: 520px) {
  .rag-files { max-height: 8rem; }
  .rag-cite-head { font-size: 0.7rem; }
}