/* Atlas — editor workspace add-ons: the docked authoring-assistant panel.
   Tokens live in app.css; the editor grid, the shared chat-bubble /
   history-item styles and the drawer shell (two views use it) live in
   views.css. */

/* --- Assistant panel ------------------------------------------------------- */

.assistant-panel {
  position: sticky;
  top: 4px;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 108px);
  padding: 0;
  overflow: hidden;
}

.assistant-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 10px 9px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.assistant-title { flex: 1; min-width: 0; margin: 0; font-size: 15px; font-weight: 600; }
.assistant-collapse { font-size: 16px; padding: 2px 9px; }

.assistant-notice {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 16px;
  background: var(--warn-bg);
  border-bottom: 1px solid var(--warn-border);
  color: var(--warn-text);
  font-size: 12px;
  font-weight: 500;
}

/* The model switch's own row, between the AI notice and the thread: it steers
   both Send and Propose a new version, so it belongs to the panel rather than
   to either button. */
.assistant-model {
  display: flex;
  justify-content: flex-end;
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
}

/* The meter (board tasks 71 + 72) inside the panel. The strip itself is styled
   once in views.css and shared with Test Fred; what is here is only its fit in a
   276px column - it takes the panel's own gutter and a rule under it, so it
   reads as one more row of the panel's chrome rather than as the first line of
   the conversation.

   `justify-content: center` because the column is narrow enough that a
   left-aligned row of four short parts looks like a mistake beside the
   right-aligned model switch above it. */
.assistant-panel .chat-meter {
  margin: 0;
  padding: 6px 12px;
  justify-content: center;
  border-bottom: 1px solid var(--border);
}

.assistant-thread {
  flex: 1;
  min-height: 220px;
  overflow-y: auto;
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.assistant-thread .bubble { max-width: 92%; font-size: 13.5px; }
.assistant-empty { margin: auto; text-align: center; padding: 0 18px; }

/* The limit notice, and the way out of it (board task 52). A column so the
   button sits under its own sentence at every width: a row of prose plus a
   button is exactly the row that gets sliced off at 390px, and this one is the
   only thing on screen that can end the dead end (footgun 34). */
.assistant-capped {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  margin: 0 12px 10px;
  text-align: center;
  color: var(--text-soft);
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 9px 10px;
  font-size: 12.5px;
}

.assistant-capped-text { margin: 0; }
.assistant-capped-new { flex: 0 1 auto; min-width: 0; }

/* The approach to the cap: a quiet line above the box, in the same place
   whatever it says. Not a warning colour — it is a fact, and the moment it
   becomes a problem it is replaced by the notice above. */
.assistant-turns-left {
  margin: 0;
  color: var(--text-soft);
  font-size: 12px;
  text-align: right;
}

/* Why the last send did not happen, in the same place, until the next one
   (owner, 2026-08-24). Left-aligned and warning-coloured where `turns-left` is
   right-aligned and quiet: that one is a fact you may ignore, this one is the
   answer to "where did my message go" and has to be findable by somebody who
   came back to the screen minutes later. */
.assistant-failed {
  margin: 0 0 2px;
  padding: 7px 9px;
  border-radius: var(--radius-sm);
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-text);
  font-size: 12px;
  line-height: 1.45;
}

/* A column, not a row: the composer sends two different things now (a message,
   and a request for a whole new file), and two buttons beside a growing textarea
   is exactly the row that gets sliced off at 390px. */
.assistant-composer {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px 8px;
  border-top: 1px solid var(--border);
}

.assistant-composer .chat-input { min-height: 40px; font-size: 13.5px; }

.assistant-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.assistant-actions .assistant-attach { margin-right: auto; padding-left: 0; }

/* --- The assistant's tint, one per model (board task 63) -------------------------
   Owner, 2026-07-31, in two rounds: "a slightly different shade to the chat
   window… one for each model. Nothing too garish" — then "the buttons for
   Haiku, Sonnet and Opus should also reflect the background colour, and the
   header that sits just behind the buttons should match the theming of the
   text chat."

   So three things wear the tint and nothing else does: the THREAD's paper, the
   STRIP the switch sits in, and the switch's own buttons — each button always
   in its model's shade, so the mapping colour->model is taught by the control
   itself. Bubbles, text and every other button are untouched. Haiku is cool
   green-grey, Sonnet neutral, Opus warm.

   `is-model-*` is set by `views/fred/assistant.js` from the SAME key the switch
   writes, so a fourth model is one block of rules here. */
.assistant-thread, .assistant-model { transition: background 0.25s ease; }

.assistant-panel.is-model-haiku :is(.assistant-thread, .assistant-model) { background: #eef4f0; }
.assistant-panel.is-model-sonnet :is(.assistant-thread, .assistant-model) { background: var(--surface); }
.assistant-panel.is-model-opus :is(.assistant-thread, .assistant-model) { background: #f8f1e5; }

/* Each choice wears its own model's shade at all times; being chosen deepens it
   and draws the ring. The colours hold outside this panel too (the study-notes
   switch), because a colour that means "Opus" on one screen must not mean
   nothing on another. */
.ai-switch-choice[data-model="haiku"] { background: #e3ede7; color: #3d5a4c; }
.ai-switch-choice[data-model="sonnet"] { background: #efe9e0; color: #5c544a; }
.ai-switch-choice[data-model="opus"] { background: #f3e4cd; color: #6d5426; }

.ai-switch-choice.is-on { box-shadow: inset 0 0 0 1.5px currentColor; font-weight: 700; }
.ai-switch-choice:not(.is-on) { opacity: 0.6; }
.ai-switch-choice:hover { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .assistant-thread, .assistant-model { transition: none; }
}

/* --- Proposal cards (board task 63) ----------------------------------------------
   A page the assistant WROTE, drawn under its bubble with the one button that
   makes it real. The design brief is on the card: the destination is stated in
   monospace and comes from the server, the page is readable before it is kept,
   and nothing reaches Fred except through the button.

   Distinct from a bubble on purpose — left-accented, full width, on the panel's
   surface — because a card is not something the assistant SAID, it is something
   it MADE. */
.proposal {
  margin: 2px 0 6px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
}

.proposal.is-saved { border-left-color: var(--border-strong); background: var(--surface-2); }

.proposal-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.proposal-kind {
  flex: none;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

.proposal-name { font-weight: 600; font-size: 13.5px; overflow-wrap: anywhere; }
.proposal-rename { flex: 1; min-width: 120px; font-size: 13px; padding: 4px 9px; }

.proposal-dest {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 7px;
  font-size: 11.5px;
}

.proposal-dest-label {
  color: var(--text-soft);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10px;
  font-weight: 700;
}

/* The one thing on the card that must not be mistaken for prose. */
.proposal-path {
  font-family: var(--font-mono);
  font-size: 11.5px;
  background: var(--accent-soft);
  color: var(--accent-strong);
  border-radius: 4px;
  padding: 1px 6px;
  word-break: break-all;
}

/* The shrink alarm: a replacement that deletes a share of the page says so in
   words, because a red-and-green diff is developer furniture and the authors
   are therapists. Amber, not red — it is a thing to check, not a verdict. */
.proposal-warn {
  margin: 8px 0 0;
  padding: 7px 10px;
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  border-radius: var(--radius-sm);
  color: var(--warn-text);
  font-size: 12px;
  line-height: 1.45;
}

.proposal-warn-inline { color: var(--warn-text); font-size: 11.5px; font-weight: 600; }
.proposal-warn-inline[hidden] { display: none; }

/* A proposal the page already matches: nothing to review, nothing to save, and
   nothing alarming either — so it is stated quietly and the card stands down
   to the same grey a saved one wears (owner, 2026-07-31). */
.proposal.is-settled { border-left-color: var(--border-strong); background: var(--surface-2); }
.proposal-settled { margin: 8px 0 0; color: var(--text-soft); font-size: 12px; line-height: 1.45; }

.proposal-reading { margin-top: 4px; }
.proposal-read { padding-left: 0; }

/* The page itself, read before it is kept. Capped and scrollable: a whole
   chapter's worth of proposal must not swallow the thread. */
.proposal-body {
  margin-top: 6px;
  padding: 9px 11px;
  max-height: 34vh;
  overflow-y: auto;
  background: #fbf6ea;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  line-height: 1.5;
}

.proposal-body[hidden] { display: none; }
.proposal-body > :first-child { margin-top: 0; }
.proposal-body :is(h1, h2, h3, h4) {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--accent-strong);
  margin: 0.9em 0 0.3em;
  font-size: 13.5px;
}

.proposal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.assistant-hint { margin: 0; padding: 0 16px 10px; color: var(--text-soft); font-size: 11.5px; }

/* --- Attached documents (board task 59) ----------------------------------------
   The books this conversation is holding, above the box you type in: what the
   assistant can SEE belongs beside what you are about to say to it. Empty most
   of the time, and it takes no room at all when it is (`:empty`), because a
   permanent gap above the composer would cost the thread a line of history. */
.assistant-attached { display: flex; flex-wrap: wrap; gap: 6px; }
.assistant-attached:empty { display: none; }

/* What is wrong with an attached book on the model currently selected. It takes
   the whole row rather than sitting beside the chips, because it is a sentence
   to read and not a token to scan — and the switch it tells you to use is two
   rows up. `.muted` on the scan note is what separates the two: one is a
   refusal waiting to happen, the other is a caveat she may accept. */
.assistant-warn {
  flex: 1 0 100%;
  margin: 0;
  color: var(--warn-text);
  line-height: 1.4;
}
.assistant-warn.muted { color: var(--text-soft); }

.assistant-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding-right: 3px;
  border: 1px solid var(--border-strong);
  color: var(--text);
}

/* Ellipsis rather than wrap: a book's filename can be longer than this panel is
   wide, and a chip that grows to three lines pushes the composer off screen. */
.assistant-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.assistant-chip-x {
  flex: none;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: 14px;
  line-height: 1;
  padding: 1px 5px;
  color: var(--text-soft);
  cursor: pointer;
}

.assistant-chip-x:hover { background: var(--danger-soft); color: var(--danger-strong); }
.assistant-chip-x:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }

/* --- A highlighted passage (owner, 2026-07-31) ----------------------------------
   Words the author picked out in the editor, quoted above what they are about
   to type. It belongs in the composer for the same reason the attached books
   do: this is what the assistant will be looking at when it reads the message.
   It rides ONE send and then goes, so it is drawn as a quotation rather than as
   a chip — a quotation is obviously about to be spent. */
.assistant-selection {
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: 6px 9px;
}
.assistant-selection[hidden] { display: none; }

.assistant-selection-head { display: flex; align-items: center; gap: 6px; }

.assistant-selection-label {
  flex: 1;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-strong);
}

/* Capped and scrollable: a therapist can highlight half a page, and the
   composer must not be pushed off the bottom of the panel by the quotation. */
.assistant-selection-text {
  margin: 4px 0 0;
  max-height: 6.4em;
  overflow-y: auto;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-soft);
  white-space: pre-wrap;
}

/* --- Picking a document to attach ------------------------------------------------
   A list, not a dropdown: the therapist is choosing between documents they know
   by name, and one already attached has to look unavailable rather than be
   refused after the click. */
.attach-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 10px 0 4px;
  max-height: 46vh;
  overflow-y: auto;
}

.attach-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: inherit;
  color: var(--text);
  cursor: pointer;
}

.attach-row:hover:not(:disabled) { border-color: var(--accent); background: var(--accent-soft); }
.attach-row:focus-visible { outline: var(--focus-ring); outline-offset: 1px; }
.attach-row:disabled { cursor: default; opacity: 0.55; background: var(--surface-2); }

/* Nudges the "New conversation" button after a 409 (session cap reached). */
.assistant-attention {
  color: var(--accent-strong);
  border-color: var(--accent);
  animation: attention-pulse 1.4s ease-in-out 3;
}

@keyframes attention-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(94, 130, 114, 0); }
  50% { box-shadow: 0 0 0 6px rgba(94, 130, 114, 0.22); }
}

/* --- Responsive --------------------------------------------------------------- */

@media (max-width: 1100px) {
  .assistant-panel { position: static; max-height: none; }
  .assistant-thread { min-height: 160px; max-height: 48vh; }
}
