/* ============================================================
   Cadry copilot — right-to-left slide-over sidebar.
   Uses the shared design tokens (design.css). Additive, except the
   launcher clearance gutter applied to .page / .settings-page when
   the FAB is mounted (see --cop-launch-clearance-* below).
   ============================================================ */

/* Launcher footprint. Pages that mount .cop (see application layout) pad their
   content by --cop-launch-clearance-* so primary CTAs, team-card badges, and
   the last chart point never sit under the 46px disc. Tokens live here — next
   to the button they describe — so a size/gap change updates the gutter too.
   env(safe-area-inset-*) keeps the same corner clear of the iOS home indicator. */
:root {
  --cop-launch-size: 46px;
  --cop-launch-gap: 22px;
  --cop-launch-inset-right: max(var(--cop-launch-gap), env(safe-area-inset-right, 0px));
  --cop-launch-inset-bottom: max(var(--cop-launch-gap), env(safe-area-inset-bottom, 0px));
  --cop-launch-clearance-right: calc(var(--cop-launch-size) + var(--cop-launch-inset-right) + 16px);
  --cop-launch-clearance-bottom: calc(var(--cop-launch-size) + var(--cop-launch-inset-bottom) + 16px);
}

.cop { position: fixed; inset: 0; pointer-events: none; z-index: 60; overflow: visible; }
/* Only the launcher (and the open panel) receive clicks. `.cop > * { pointer-events:
   auto }` used to re-enable the closed panel too: it is `position: fixed` on the
   right and only visually translated off-screen, so it ate hits on Choose Scale,
   team-card badges, and the chart's latest point. */
.cop-launch,
.cop.open .cop-panel { pointer-events: auto; }

/* ---- Launcher ---- */
.cop-launch {
  position: fixed;
  right: var(--cop-launch-inset-right); bottom: var(--cop-launch-inset-bottom);
  width: var(--cop-launch-size); height: var(--cop-launch-size); border-radius: 50%;
  display: grid; place-items: center;
  color: #FFFFFF;
  background: var(--accent);
  box-shadow: 0 2px 6px rgba(21, 36, 47, 0.16), 0 8px 28px rgba(21, 36, 47, 0.18);
  transition: transform .16s ease, opacity .16s ease;
}
.cop-launch:hover { transform: translateY(-1px) scale(1.03); }
.cop-launch:active { transform: translateY(0) scale(.96); }
.cop.open .cop-launch { opacity: 0; transform: scale(.9); pointer-events: none; }

/* Reserve the launcher's corner on every signed-in page that mounts it.
   .page / .settings-page are the shells for billing, teams, metric detail,
   and the rest of the app chrome — one gutter, not a per-screen hide. */
body:has(> .cop) .page,
body:has(> .cop) .settings-page {
  padding-right: max(28px, var(--cop-launch-clearance-right));
  padding-bottom: max(48px, var(--cop-launch-clearance-bottom));
}
html:has(body > .cop) {
  scroll-padding-right: var(--cop-launch-clearance-right);
  scroll-padding-bottom: var(--cop-launch-clearance-bottom);
}

/* ---- Panel ----
   A floating card inset from the viewport edges (artboard 08), not a flush
   full-height sheet. The OUTER box only slides — overflow+radius live on
   .cop-panel-body. Putting overflow:clip on the same node as the translate
   made Chromium/WebKit clip the open panel to a stale compositor layer, so
   the right edge of every reply (and the send button) disappeared.
   Closed transform overshoots by the inset + shadow so nothing peeks in.
   max-width keeps the 320px clamp from overflowing a narrow containing block
   (classic scrollbars, 100% of .cop, visual viewport). */
.cop-panel {
  /* --cop-panel-width is the default clamp until the reader drags; JS then
     writes a pixel value onto this same custom property so the size sticks.
     top clears the 48px topbar so a max-width drag cannot cover search or
     account; the 16px gap matches the side/bottom inset. Phone sheet below
     still goes full-bleed via inset: 0. */
  --cop-panel-width: clamp(320px, 31vw, 412px);
  position: fixed; top: calc(var(--topbar-height, 48px) + 16px); right: 16px; bottom: 16px;
  width: var(--cop-panel-width);
  max-width: calc(100% - 32px);
  transform: translateX(calc(100% + 48px));
  transition: transform .26s cubic-bezier(.32, .72, 0, 1);
}
.cop.open .cop-panel { transform: translateX(0); }
.cop-resize {
  position: absolute; left: 0; top: 0; bottom: 0; width: 10px; z-index: 3;
  padding: 0; border: 0; background: transparent; cursor: ew-resize;
  touch-action: none; user-select: none;
}
/* Quiet mid-edge grip. Hover / focus / drag lengthens it so the affordance
   is findable without spending the view's one accent moment. */
.cop-resize::after {
  content: ""; position: absolute; left: 3px; top: 50%;
  width: 3px; height: 36px; margin-top: -18px; border-radius: 2px;
  background: var(--ink-5); opacity: .75;
  transition: background .14s ease, opacity .14s ease, height .14s ease, margin-top .14s ease;
}
.cop-resize:hover::after,
.cop-resize:focus-visible::after,
.cop.resizing .cop-resize::after {
  background: var(--ink-3); opacity: 1; height: 56px; margin-top: -28px;
}
.cop-resize:focus { outline: none; }
.cop-resize:focus-visible { outline: none; }
.cop.resizing, .cop.resizing * { cursor: ew-resize !important; user-select: none; }
.cop.resizing iframe, .cop.resizing .asst-plot { pointer-events: none; }
.cop-panel-body {
  height: 100%; min-width: 0; min-height: 0;
  display: flex; flex-direction: column;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}

.cop-head {
  flex: 0 0 auto; min-height: 50px; min-width: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 16px; border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
.cop-title { display: flex; align-items: center; gap: 7px; font-weight: 600; font-size: 14px; letter-spacing: -0.01em; flex-shrink: 0; }
.cop-spark { color: var(--accent); }
.cop-head-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.cop-x { width: 26px; padding: 0; justify-content: center; position: relative; }
/* Mono text header actions ("HISTORY" / "NEW" / "FULL SCREEN"), darkening to
   ink when active. ::before pads each one to a ≥40px hit area; the horizontal
   inset stays inside the 8px gap so neighbors don't steal clicks. */
.cop-head-link {
  position: relative; padding: 4px 3px; border-radius: 6px;
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  white-space: nowrap; transition: color .14s ease;
}
.cop-head-link:hover, .cop-head-link[aria-expanded="true"] { color: var(--ink); }
.cop-head-link::before { content: ""; position: absolute; inset: -9px -2px; }
.cop-x::before { content: ""; position: absolute; inset: -7px -3px; }

/* ---- Conversation history popover ----
   A 264px card under the header's right side. Rows stack title over a mono
   meta line; the active thread gets a 2px accent left edge + "· Active". */
.cop-history {
  position: absolute; top: 54px; right: 10px; left: auto; z-index: 5;
  width: 264px; max-width: calc(100% - 20px);
  max-height: 58%; overflow-y: auto; overscroll-behavior: contain;
  background: var(--surface);
  border: 1px solid var(--rule-2); border-radius: 10px;
  box-shadow: 0 2px 6px rgba(21, 36, 47, 0.08), 0 12px 32px rgba(21, 36, 47, 0.16);
  scrollbar-width: thin;
}
.cop-history-head {
  position: sticky; top: 0; padding: 9px 12px 7px;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-4);
  background: var(--surface); border-bottom: 1px solid var(--rule);
}
.cop-history-empty {
  margin: 0; padding: 12px;
  font-size: 12.5px; color: var(--ink-3); line-height: 1.5;
}
.cop-history-list { list-style: none; margin: 0; padding: 4px; display: flex; flex-direction: column; gap: 1px; }
.cop-history-item {
  display: flex; flex-direction: column; align-items: stretch; gap: 3px;
  width: 100%; padding: 8px 10px 8px 8px; border-radius: 7px;
  border-left: 2px solid transparent;
  text-align: left; color: var(--ink-2); position: relative;
}
/* Hover/current fill crossfades via opacity (compositor) instead of background
   (paint); the state sets --hi-bg. Text color snaps. */
.cop-history-item::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--hi-bg, var(--hover)); opacity: 0; transition: opacity .12s ease; pointer-events: none; z-index: -1; }
.cop-history-item:hover::after { opacity: 1; }
/* The active thread reads as a flag: square left corners against a solid 2px
   accent edge (the design's navy bar), fog fill behind. */
.cop-history-item.current { color: var(--ink); border-left-color: var(--accent); border-radius: 0 7px 7px 0; --hi-bg: var(--surface-2); }
.cop-history-item.current::after { opacity: 1; }
.cop-history-title {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12px; font-weight: 500;
}
.cop-history-time {
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-4);
}

/* ---- Transcript ---- */
.cop-scroll {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px; display: flex; flex-direction: column; gap: 12px;
  scrollbar-width: thin;
}

.cop-msg { display: flex; max-width: 100%; }
.cop-msg.cop-user { justify-content: flex-end; }
.cop-msg.cop-assistant { justify-content: flex-start; }

.cop-bubble {
  max-width: 86%; padding: 8px 11px; border-radius: 12px;
  font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}
.cop-user .cop-bubble {
  background: var(--accent-soft); color: var(--accent-ink);
  border: 1px solid var(--accent-edge); border-bottom-right-radius: 4px;
}
/* Assistant bubble = fog on the white panel, hairline border (artboard 08). */
.cop-assistant .cop-bubble {
  background: var(--bg); color: var(--ink); border: 1px solid var(--rule);
  border-bottom-left-radius: 4px;
}

/* ---- Rendered markdown (assistant bubbles only) ----
   .cop-md is added to an assistant .cop-bubble once it holds rendered HTML.
   It turns OFF the inherited white-space: pre-wrap (which would mangle real
   block spacing) and styles block children for a 13px sidebar, reusing the
   shared design tokens. Code surfaces use --surface so they read against the
   fog (--bg) bubble. */
.cop-bubble.cop-md { white-space: normal; }
.cop-md > :first-child { margin-top: 0; }
.cop-md > :last-child { margin-bottom: 0; }

.cop-md p { margin: 0 0 .5em; }
.cop-md ul, .cop-md ol { margin: 0 0 .5em; padding-left: 1.4em; }
.cop-md li { margin: .15em 0; }
.cop-md li > ul, .cop-md li > ol { margin: .15em 0; }

.cop-md h1, .cop-md h2, .cop-md h3, .cop-md h4 {
  margin: .8em 0 .35em; line-height: 1.25; font-weight: 600; letter-spacing: -0.01em;
}
.cop-md > :first-child h1, .cop-md > h1:first-child { margin-top: 0; }
.cop-md h1 { font-size: 15px; }
.cop-md h2 { font-size: 14px; }
.cop-md h3 { font-size: 13.5px; }
.cop-md h4 { font-size: 13px; color: var(--ink-2); }

.cop-md strong { font-weight: 600; color: var(--ink); }
.cop-md em { font-style: italic; }

.cop-md a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.cop-md a:hover { color: var(--accent-ink); }

.cop-md code {
  font-family: var(--mono); font-size: 12px;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius-sm); padding: .05em .35em;
}
/* Code blocks scroll horizontally so a long or still-streaming fence never
   blows out the sidebar width. Reset the inline-code chrome inside pre. */
.cop-md pre {
  margin: 0 0 .6em; padding: .6em .7em;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); overflow-x: auto;
  white-space: pre; -webkit-overflow-scrolling: touch;
}
.cop-md pre code {
  background: none; border: 0; border-radius: 0; padding: 0;
  font-size: 12px; line-height: 1.45; color: var(--ink);
}

.cop-md blockquote {
  margin: 0 0 .6em; padding: .1em 0 .1em .7em;
  border-left: 2px solid var(--rule-3); color: var(--ink-3);
}

.cop-md hr { border: 0; border-top: 1px solid var(--rule); margin: .8em 0; }

.cop-md table {
  width: 100%; border-collapse: collapse; margin: 0 0 .6em;
  font-size: 12px; display: block; overflow-x: auto;
}
.cop-md th, .cop-md td { border: 1px solid var(--rule); padding: .3em .5em; text-align: left; }
.cop-md th { background: var(--surface); font-weight: 600; color: var(--ink-2); }

/* Blinking caret trailing the last rendered line while tokens arrive. It sits on
   the LAST block child (marked wraps even a partial line in <p>/<li>/<pre>) so it
   reads inline after the text instead of on its own line below the bubble. The
   controller drops .cop-streaming on finalize/teardown, which removes the caret. */
.cop-md.cop-streaming > :last-child::after {
  content: ""; display: inline-block; width: .5ch; height: 1em;
  background: var(--ink-3); margin-left: 1px; vertical-align: -2px;
  animation: cop-blink 1s steps(2, start) infinite;
}
@keyframes cop-blink { 50% { opacity: 0; } }

/* ---- Tool activity ledger ----
   One chip per tool burst instead of one pill per call. Running: pulsing dot +
   current tool + live count + indeterminate mini bar. Sealed: ✓/✕ + "tool ×N"
   (or "N actions"), expandable to the per-call run log. .single = a lone call,
   which keeps the plain chip (no chevron, nothing to expand). */
.cop-ledger {
  align-self: flex-start; max-width: 86%;
  display: flex; flex-direction: column; align-items: flex-start; min-width: 0;
  --cop-ok-edge: oklch(0.88 0.045 160);
  --cop-bad-edge: oklch(0.90 0.05 25);
}
.cop-ledger.open { width: 86%; }
.cop-ledger-head {
  display: inline-flex; align-items: center; gap: 7px; min-height: 24px;
  padding: 0 9px; border-radius: 12px; max-width: 100%;
  background: var(--surface-2); border: 1px solid var(--rule-2); color: var(--ink-3);
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .03em; text-transform: uppercase;
  position: relative; text-align: left;
  transition: border-radius .2s cubic-bezier(.2, 0, 0, 1), background-color .2s ease, border-color .2s ease, color .2s ease;
}
/* ≥40px hit area for a 24px chip; ±0 horizontally so it never overlaps siblings */
.cop-ledger-head::before { content: ""; position: absolute; inset: -8px 0; }
.cop-ledger.done .cop-ledger-head { background: var(--ok-soft); border-color: var(--cop-ok-edge); color: var(--ok-ink); }
.cop-ledger.error .cop-ledger-head { background: var(--bad-soft); border-color: var(--cop-bad-edge); color: var(--bad-ink); }
.cop-ledger.single .cop-ledger-head { cursor: default; }
.cop-ledger-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cop-ledger.open .cop-ledger-head { width: 100%; border-radius: 10px 10px 0 0; }
.cop-ledger.open .cop-ledger-label { flex: 1 1 auto; }

/* Status glyph: ●/✓/✕ all live stacked in one slot and cross-fade
   (opacity + scale + blur) when the state class flips — never a hard swap. */
.cop-glyph { position: relative; width: 10px; height: 10px; flex: 0 0 auto; }
.cop-g {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 9px; line-height: 1;
  opacity: 0; scale: .25; filter: blur(4px);
  transition: opacity .3s cubic-bezier(.2, 0, 0, 1), scale .3s cubic-bezier(.2, 0, 0, 1), filter .3s cubic-bezier(.2, 0, 0, 1);
}
.cop-g-run::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); animation: cop-pulse 1s ease-in-out infinite;
}
.cop-g-done { color: var(--ok-ink); }
.cop-g-fail { color: var(--bad-ink); }
.cop-ledger.running > .cop-ledger-head .cop-g-run,
.cop-ledger.done > .cop-ledger-head .cop-g-done,
.cop-ledger.error > .cop-ledger-head .cop-g-fail,
.cop-ledger-row.running .cop-g-run,
.cop-ledger-row.done .cop-g-done,
.cop-ledger-row.error .cop-g-fail,
.cop-ledger-row.denied .cop-g-fail { opacity: 1; scale: 1; filter: blur(0); }

/* Indeterminate mini progress bar, running state only */
.cop-ledger-bar {
  width: 48px; height: 3px; border-radius: 2px; flex: 0 0 auto;
  background: var(--rule-2); overflow: hidden; position: relative;
}
.cop-ledger-fill {
  position: absolute; inset: 0; width: 40%; border-radius: 2px;
  background: var(--accent); animation: cop-scan 1.1s cubic-bezier(.4, 0, .6, 1) infinite;
}
@keyframes cop-scan { 0% { translate: -110% 0; } 100% { translate: 280% 0; } }
.cop-ledger:not(.running) .cop-ledger-bar { display: none; }

/* Chevron appears once the burst settles; rotates open. */
.cop-ledger-chev { flex: 0 0 auto; transition: rotate .26s cubic-bezier(.2, 0, 0, 1); }
.cop-ledger.running .cop-ledger-chev, .cop-ledger.single .cop-ledger-chev { display: none; }
.cop-ledger.open .cop-ledger-chev { rotate: 180deg; }

/* Run log: interruptible grid-template-rows expand (no keyframes). */
.cop-ledger-log {
  display: grid; grid-template-rows: 0fr; width: 0; min-width: 100%;
  transition: grid-template-rows .26s cubic-bezier(.2, 0, 0, 1);
}
.cop-ledger.open .cop-ledger-log { grid-template-rows: 1fr; }
.cop-ledger-rows { min-height: 0; overflow: clip; display: flex; flex-direction: column; }
.cop-ledger-row {
  display: flex; align-items: center; gap: 8px; min-height: 26px; padding: 0 11px;
  background: var(--surface);
  border-left: 1px solid var(--rule-2); border-right: 1px solid var(--rule-2);
  font-size: 12px; color: var(--ink-2);
}
.cop-ledger-row + .cop-ledger-row { border-top: 1px solid var(--rule); }
.cop-ledger-row:first-child { border-top: 1px solid var(--rule-2); border-radius: 10px 10px 0 0; margin-top: 4px; }
.cop-ledger-row:last-child { border-bottom: 1px solid var(--rule-2); border-radius: 0 0 10px 10px; }
.cop-ledger.open .cop-ledger-row:first-child { margin-top: -1px; border-top: 0; border-radius: 0; }
.cop-ledger-row-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cop-ledger-row.denied .cop-ledger-row-text, .cop-ledger-row.error .cop-ledger-row-text { color: var(--bad-ink); }

/* The run log's tool-kind lane (artboard 08b): a fixed-width trailing tag
   naming the tool kind — GRID / WEB / CODE — in place of a per-row count slot.
   Only a MIXED burst shows the lane; a same-tool burst's rows stay unlabeled. */
.cop-ledger-row-kind {
  flex: 0 0 auto; width: 34px; text-align: right;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .03em; text-transform: uppercase; color: var(--ink-4);
  display: none;
}
.cop-ledger.mixed .cop-ledger-row-kind { display: block; }

@keyframes cop-pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* ---- Sources row (artboard 08b) ----
   Citations under a cited reply: a quiet mono SOURCES label + white domain
   pills (accent dot + domain), first three + "+N" overflow. Pills are links —
   new tab, title = the cited page. Chips stagger in ~60ms apiece (the JS sets
   animation-delay); hydrated transcripts render them static. */
.cop-sources {
  align-self: flex-start; max-width: 86%;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-top: -5px; padding-left: 2px;
}
.cop-sources-label, .cop-sources-more {
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
  flex: 0 0 auto;
}
/* "+N" is a button: a dashed pill that expands the hidden pills in place. */
.cop-sources-more {
  letter-spacing: 0; height: 18px; padding: 0 7px;
  border: 1px dashed var(--rule-3); border-radius: 9px;
  transition: border-color .14s ease, color .14s ease;
}
.cop-sources-more:hover { border-color: var(--accent); color: var(--ink-2); }
.cop-source.cop-source-hidden { display: none; }
.cop-source {
  display: inline-flex; align-items: center; gap: 5px;
  height: 18px; padding: 0 8px; border-radius: 9px;
  background: var(--surface); border: 1px solid var(--rule-2);
  text-decoration: none;
  transition: border-color .14s ease;
}
.cop-source:hover { border-color: var(--rule-3); }
.cop-source-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex: 0 0 auto; }
.cop-source-domain {
  font-family: var(--mono); font-size: 9px; font-weight: 500; color: var(--ink-3);
  max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- Inline cited spans (artboard 08b: citations live where the claim is) ----
   A cited span gets a quiet dashed underline; hover raises the source card
   (below); click opens the first source. */
.cop-cited {
  position: relative; cursor: pointer;
  text-decoration: underline dashed 1px;
  text-decoration-color: color-mix(in oklab, var(--accent) 55%, transparent);
  text-underline-offset: 3px;
  transition: text-decoration-color .14s ease, background-color .14s ease;
}
.cop-cited:hover { text-decoration-color: var(--accent); background: var(--accent-soft); }

/* ---- Hover cards (source card + whisper popover) ----
   Appended INSIDE their anchor (so hover containment is free), floated below
   it. ~150ms hover intent is handled in JS; the appearance is a 120ms fade. */
.cop-card {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 6;
  background: var(--surface); border: 1px solid var(--rule-2); border-radius: 8px;
  box-shadow: 0 2px 6px rgba(21, 36, 47, 0.08), 0 10px 28px rgba(21, 36, 47, 0.14);
  animation: cop-card-in .12s ease backwards;
  font-family: var(--sans); font-size: 12px; font-weight: 400;
  letter-spacing: 0; text-transform: none; white-space: normal;
  text-decoration: none; cursor: default;
}
@keyframes cop-card-in { from { opacity: 0; translate: 0 2px; } }

.cop-source-card { display: flex; flex-direction: column; padding: 4px; min-width: 220px; max-width: 300px; }
/* The card can live inside a .cop-md bubble — shield it from the link styles. */
.cop-md .cop-source-card-row, .cop-source-card-row {
  display: flex; align-items: center; gap: 7px; min-height: 26px;
  padding: 0 7px; border-radius: 6px; color: var(--ink-4); min-width: 0;
  text-decoration: none;
}
.cop-source-card-row .cop-source-domain { flex: 0 0 auto; }
.cop-source-card-row:hover { background: var(--hover); }
.cop-source-card-title {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11.5px; color: var(--ink-2);
}
.cop-source-card-row svg { flex: 0 0 auto; }

/* ---- Memory whisper (artboard 08b) ----
   A memory write is never a ledger chip: a borderless "✦ REMEMBERED · note"
   whisper fades in under the reply (~200ms after it settles — the JS sets the
   delay). The inline note is the digest; hover raises a popover with the full
   saved note, its path, and FORGET. */
.cop-whisper {
  align-self: flex-start; max-width: 100%; position: relative;
  display: flex; align-items: center; gap: 7px; padding-left: 2px;
}
.cop-whisper-mark { color: var(--accent); font-family: var(--mono); font-size: 10px; line-height: 1; flex: 0 0 auto; }
.cop-whisper-label {
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
  flex: 0 0 auto;
}
.cop-whisper-note {
  font-size: 12px; color: var(--ink-3); line-height: 1.25;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.cop-whisper-card {
  left: 16px; display: flex; flex-direction: column; gap: 6px;
  width: 290px; max-width: 84vw; padding: 9px 11px 8px;
}
.cop-whisper-card-note { font-size: 11.5px; line-height: 16px; color: var(--ink-2); white-space: pre-wrap; word-break: break-word; }
.cop-whisper-card-foot { display: flex; align-items: center; gap: 8px; }
.cop-whisper-card-path {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: 8.5px; font-weight: 500; color: var(--ink-4);
}
.cop-whisper-forget {
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--bad-ink);
  padding: 2px 3px; border-radius: 4px; flex: 0 0 auto; position: relative;
}
.cop-whisper-forget:hover { background: var(--bad-soft); }
.cop-whisper-forget::before { content: ""; position: absolute; inset: -8px -4px; } /* ≥24px hit area for a 9px word */

/* ---- Enter/exit motion ----
   .cop-in is added ONLY to live-appended turns (never hydrated transcripts), so
   nothing animates on load. Exits (.cop-out) are softer than enters. */
.cop-in { animation: cop-enter .26s cubic-bezier(.2, 0, 0, 1) backwards; }
@keyframes cop-enter { from { opacity: 0; translate: 0 5px; } }
.cop-out { opacity: 0; translate: 0 4px; transition: opacity .18s ease, translate .18s ease; pointer-events: none; }

/* ---- Thinking dots ---- */
.cop-thinking { align-self: flex-start; display: inline-flex; gap: 4px; padding: 9px 12px; }
.cop-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-4); animation: cop-bounce 1.2s ease-in-out infinite; }
.cop-dot:nth-child(2) { animation-delay: .15s; }
.cop-dot:nth-child(3) { animation-delay: .3s; }
@keyframes cop-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-4px); opacity: 1; } }

/* ---- Confirm card ----
   Amber soft fill with a soft amber edge (#E5D4B0 per artboard 08), not the
   full-strength warn border. */
.cop-confirm {
  align-self: stretch; border: 1px solid #E5D4B0;
  background: var(--warn-soft); border-radius: var(--radius-lg);
  padding: 11px 12px; display: flex; flex-direction: column; gap: 8px;
}
.cop-confirm-head { font-weight: 600; font-size: 12.5px; color: var(--warn-ink); }
.cop-confirm-list { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; color: var(--ink-2); }
.cop-confirm-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Pressed, waiting on the server. The card holds its place — it only leaves once
   the answer arrives — so the busy state has to read as "working", not "gone". */
.cop-confirm.cop-busy .cop-confirm-list { opacity: .65; }
.cop-confirm.cop-busy .btn[disabled] { cursor: progress; }
.cop-confirm-spin {
  width: 12px; height: 12px; margin-right: auto; align-self: center;
  border-radius: 50%; border: 1.5px solid var(--warn-ink); border-top-color: transparent;
  animation: cop-spin .7s linear infinite;
}
@keyframes cop-spin { to { rotate: 360deg; } }

/* ---- Error line ---- */
.cop-error {
  align-self: stretch; font-size: 12.5px; color: var(--bad-ink);
  background: var(--bad-soft); border: 1px solid var(--bad-soft);
  border-radius: var(--radius); padding: 8px 10px;
}

/* ---- Empty state ("where NEW lands") ----
   Centered brand roundel + serif greeting + suggestion prompt cards that seed
   the composer. The blank-workspace welcome is this same state, full-page. */
.cop-empty { margin: auto 0; text-align: center; padding: 18px 8px; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.cop-empty-mark {
  width: 44px; height: 44px; border-radius: 50%; margin-bottom: 8px;
  display: grid; place-items: center; color: #FFFFFF;
  background: var(--accent);
  box-shadow: 0 2px 6px rgba(21, 36, 47, 0.16), 0 8px 28px rgba(21, 36, 47, 0.18);
}
.cop-empty-title { font-family: var(--serif); font-weight: 500; font-size: 20px; letter-spacing: -0.01em; margin: 0; text-wrap: balance; }
.cop-empty-sub { font-size: 13px; color: var(--ink-3); margin: 0; max-width: 32ch; line-height: 1.5; text-wrap: pretty; }
.cop-suggest { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; width: 100%; max-width: 300px; }
.cop-chip-suggest {
  text-align: left; font-size: 13px; color: var(--ink-2); line-height: 1.3;
  padding: 11px 13px; border-radius: 10px; background: var(--surface);
  border: 1px solid var(--rule-2); box-shadow: var(--shadow-1);
  position: relative;
  transition: scale .14s cubic-bezier(.2, 0, 0, 1), border-color .14s ease;
}
/* Hover tint via opacity crossfade (compositor) instead of background (paint). */
.cop-chip-suggest::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--surface-2); opacity: 0; transition: opacity .12s ease; pointer-events: none; z-index: -1; }
.cop-chip-suggest:hover::after { opacity: 1; }
.cop-chip-suggest:hover { border-color: var(--rule-3); }
.cop-chip-suggest:active { scale: .96; }

/* ---- Composer ---- */
.cop-composer {
  flex: 0 0 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px;
  padding: 10px 16px 12px; border-top: 1px solid var(--rule); background: var(--surface);
}
.cop-composer-row { display: flex; align-items: flex-end; gap: 8px; min-width: 0; }
.cop-composer textarea {
  flex: 1 1 auto; min-width: 0; resize: none; max-height: 140px;
  padding: 10px 13px; border-radius: 10px; border: 1px solid var(--rule-2);
  background: var(--bg); font-size: 13px; line-height: 1.45; color: var(--ink);
  font-family: var(--sans);
}
.cop-composer textarea::placeholder { color: var(--ink-4); }
.cop-composer textarea:focus { outline: none; border-color: var(--accent-edge); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-soft); }
.cop-composer textarea:disabled { opacity: .6; cursor: not-allowed; }
.cop-send {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 10px;
  display: grid; place-items: center; color: #FFFFFF; background: var(--accent);
  position: relative; transition: transform .1s;
}
/* Hover darken crossfades via opacity (compositor) instead of background (paint);
   the press scale stays S-tier transform. */
.cop-send::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: #000; opacity: 0; transition: opacity .12s ease; pointer-events: none; z-index: -1; }
.cop-send:hover::after { opacity: 1; }
.cop-send:active { transform: scale(.96); }
.cop.busy .cop-send, .cop-send:disabled { opacity: .5; pointer-events: none; }

/* ---- Attachments (artboard 08c) ----
   Files stage as manifest chips in a tray above the textarea, the whole panel
   is the drop target, and sent files ride as tags atop the user bubble. */
.cop-attach {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 10px;
  display: grid; place-items: center; color: var(--ink-3);
  background: var(--surface); border: 1px solid var(--rule-2);
  transition: color .14s ease, border-color .14s ease, transform .1s;
}
.cop-attach:hover { color: var(--ink); border-color: var(--rule-3); }
.cop-attach:active { transform: scale(.96); }
.cop.busy .cop-attach, .cop-welcome.busy .cop-attach { opacity: .5; pointer-events: none; }

.cop-tray { display: flex; flex-wrap: wrap; gap: 6px; }
/* Chip radius math is concentric: chip 8 = thumb 5 + 3px pad. */
.cop-chip {
  display: flex; align-items: center; gap: 7px; height: 36px;
  padding: 4px 6px 4px 4px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--rule-2);
  max-width: 100%;
}
.cop-chip-thumb {
  width: 28px; height: 28px; border-radius: 5px; object-fit: cover; flex: 0 0 auto;
  outline: 1px solid rgba(0, 0, 0, 0.1); outline-offset: -1px;
}
.cop-chip-glyph { color: var(--ink-4); flex: 0 0 auto; margin-left: 4px; }
.cop-chip-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cop-chip-name {
  font-size: 11px; font-weight: 500; line-height: 13px; color: var(--ink-2);
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cop-chip-size {
  font-family: var(--mono); font-size: 9px; font-weight: 500; line-height: 11px;
  color: var(--ink-4); font-variant-numeric: tabular-nums;
}
/* The × is 18px visually but carries a ≥40px hit area via ::before. */
.cop-chip-x {
  position: relative; width: 18px; height: 18px; border-radius: 5px;
  display: grid; place-items: center; color: var(--ink-4); flex: 0 0 auto;
  transition: color .14s ease, transform .1s;
}
.cop-chip-x::before { content: ""; position: absolute; inset: -11px; }
.cop-chip-x:hover { color: var(--ink); }
.cop-chip-x:active { transform: scale(.96); }
.cop-chip-error {
  height: auto; min-height: 28px; padding: 5px 10px;
  background: oklch(0.96 0.02 25); border-color: oklch(0.86 0.05 25);
  color: oklch(0.42 0.12 25); font-size: 11px; font-weight: 500; line-height: 14px;
}

/* Drop scrim: the whole panel is the target. The dashed inset is concentric
   with the panel (panel 12 − 6px inset ≈ 8). Fades on opacity only. */
.cop-drop {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none;
  transition: opacity .16s ease;
}
.cop.dragging .cop-drop, .cop-welcome.dragging .cop-drop { opacity: 1; transition-duration: .12s; }
.cop-drop-zone {
  position: absolute; inset: 6px; border-radius: 8px;
  border: 1.5px dashed var(--accent);
  background: color-mix(in srgb, var(--accent) 4%, transparent);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
}
.cop-drop-mark {
  width: 44px; height: 44px; border-radius: 12px; color: var(--accent);
  display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--rule-2); box-shadow: var(--shadow-pop);
}
.cop-drop-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.cop-drop-sub {
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: .1em; color: var(--ink-3); text-transform: uppercase;
}

/* Sent cargo: compact tags flush above the user bubble, in its tint family. */
.cop-msg:has(.cop-files) { flex-direction: column; align-items: flex-end; gap: 5px; }
.cop-files { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 5px; }
.cop-file {
  display: flex; align-items: center; gap: 6px; height: 28px;
  padding: 3px 8px 3px 3px; border-radius: 7px;
  background: var(--accent-soft); border: 1px solid var(--accent-edge);
}
.cop-file-thumb {
  width: 22px; height: 22px; border-radius: 5px; object-fit: cover; flex: 0 0 auto;
  outline: 1px solid rgba(0, 0, 0, 0.1); outline-offset: -1px;
}
.cop-file-glyph { color: var(--accent-ink); flex: 0 0 auto; margin-left: 4px; }
.cop-file-name {
  font-size: 10.5px; font-weight: 500; line-height: 13px; color: var(--accent-ink);
  max-width: 170px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- Mobile ----
   Full-bleed sheet. `inset: 0; width: auto` — not 100vw, which includes the
   classic scrollbar and clipped the send button / replies at the right edge.
   The open sheet stacks above the sticky topbar (z 70) so History / New /
   Full screen / ✕ stay hittable. Desktop keeps .cop at 60 so a max-width
   panel cannot cover search or account (#242). */
@media (max-width: 640px) {
  :root { --cop-launch-gap: 16px; }
  .cop-panel { inset: 0; width: auto; max-width: none; }
  .cop-panel-body { border-radius: 0; border: 0; }
  .cop-resize { display: none; }
  .cop.open { z-index: 80; }
}

@media (prefers-reduced-motion: reduce) {
  .cop-panel, .cop-ledger-log, .cop-ledger-chev, .cop-g, .cop-ledger-head, .cop-drop { transition: none; }
  .cop-dot, .cop-g-run::before, .cop-ledger-fill, .cop-in, .cop-card,
  .cop-confirm-spin,
  .cop-md.cop-streaming > :last-child::after { animation: none; }
  /* A stopped ring with one side missing reads as broken, not as waiting —
     close the gap so the still form is a plain dot. */
  .cop-confirm-spin { border-top-color: var(--warn-ink); }
}

/* ============================================================
   Model + effort picker (.mdl-*) — the chip under every composer.

   Shared by all three assistant surfaces (page dock, sidebar, first-run
   welcome), which is why it lives here rather than in chat.css.

   It never takes the accent: the composer already spends the view's one
   accent moment on Send. The chip is mono, at the run log's weight, so it
   reads as instrumentation rather than as a second control competing with
   the button beside it. Only the popover's checkmark is accent — the one
   place the reader is choosing, not reading.
   ============================================================ */
.mdl-row { display: flex; align-items: center; gap: 6px; padding: 0 4px 2px; }
.mdl-hint {
  margin-left: auto; white-space: nowrap;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
}
/* In the sidebar the composer pads its own rows, so the chip's hit box takes
   the same left edge as the paperclip above it instead of adding an indent of
   its own. */
.cop-composer .mdl-row { padding: 2px 0 0; }
.mdl-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.mdl-wrap { position: relative; }

.mdl-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 26px; padding: 0 9px;
  border: 1px solid transparent; border-radius: 8px; background: transparent;
  color: var(--ink-3);
  font-family: var(--mono); font-size: 10px; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
  /* The chip is one line at every width. Wrapped, "OPUS / 5 · HIGH" reads as
     two broken labels rather than one reading of the state. */
  white-space: nowrap;
  transition: color .12s ease, border-color .12s ease, background-color .12s ease;
}
.mdl-btn:hover { color: var(--ink); background: var(--surface-2); }
.mdl-wrap.open .mdl-btn { color: var(--ink); background: var(--surface-2); border-color: var(--rule-2); }
.mdl-btn[disabled] { cursor: default; }
.mdl-btn[disabled]:hover { color: var(--ink-3); background: transparent; }

/* The diamond is the assistant's mark at this size — a spark would be
   unreadable at 7px and a dot would say nothing. */
.mdl-diamond {
  width: 7px; height: 7px; flex: 0 0 auto; background: var(--ink-4);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.mdl-btn:hover .mdl-diamond, .mdl-wrap.open .mdl-diamond { background: var(--ink-2); }
.mdl-dot { color: var(--ink-5); }
.mdl-chev { opacity: .65; flex: 0 0 auto; }

/* Four rising bars: effort is a ladder, and the word alone makes the reader
   remember where "medium" sits on it. */
.mdl-meter { display: inline-flex; align-items: flex-end; gap: 2px; height: 10px; }
.mdl-meter i { width: 2.5px; border-radius: 1px; background: var(--rule-3); }
.mdl-meter i:nth-child(1) { height: 4px; }
.mdl-meter i:nth-child(2) { height: 6px; }
.mdl-meter i:nth-child(3) { height: 8px; }
.mdl-meter i:nth-child(4) { height: 10px; }
.mdl-meter[data-level="1"] i:nth-child(-n+1),
.mdl-meter[data-level="2"] i:nth-child(-n+2),
.mdl-meter[data-level="3"] i:nth-child(-n+3),
.mdl-meter[data-level="4"] i:nth-child(-n+4) { background: var(--ink-3); }

/* Opens UPWARD by default: every composer this sits in is at the bottom of
   its surface. `.up` flips it for anything that isn't. */
.mdl-pop {
  position: absolute; bottom: calc(100% + 8px); left: 0; z-index: 20;
  width: 288px; padding: 5px; display: none;
  background: var(--surface); border: 1px solid var(--rule-2);
  border-radius: 10px; box-shadow: var(--shadow-pop);
}
.mdl-pop.up { bottom: auto; top: calc(100% + 8px); }
.mdl-wrap.open .mdl-pop { display: block; animation: cop-card-in .12s ease backwards; }
.mdl-pop-label {
  padding: 8px 9px 5px;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-4);
}
.mdl-opt {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 9px;
  border: 0; border-radius: 7px; background: transparent;
  text-align: left; cursor: pointer;
}
.mdl-opt:hover { background: var(--hover); }
.mdl-opt-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.mdl-opt-name { font-size: 12.5px; font-weight: 500; color: var(--ink); }
.mdl-opt-sub { font-size: 11px; line-height: 1.35; color: var(--ink-4); }
.mdl-check { flex: 0 0 auto; color: var(--accent); opacity: 0; }
.mdl-opt.on .mdl-check { opacity: 1; }

.mdl-pop .seg { display: flex; margin: 0 5px 4px; }
.mdl-pop .seg .si {
  flex: 1 1 0; justify-content: center; padding: 0 4px;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase;
}
.mdl-pop .seg .si[disabled] { opacity: .45; cursor: not-allowed; }

.mdl-pop-foot {
  display: flex; align-items: center; gap: 8px;
  margin-top: 4px; padding: 8px 10px 7px;
  border-top: 1px solid var(--rule);
  font-size: 11px; line-height: 1.45; color: var(--ink-4);
}
.mdl-pop-foot .kbd { margin-left: auto; flex: 0 0 auto; }
.mdl-lock {
  font-family: var(--mono); font-size: 8.5px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
  border: 1px solid var(--rule-2); border-radius: 999px; padding: 1px 6px;
}

/* The way back to the workspace default. Only present once the thread has a
   pick of its own, so the popover stays two choices deep until it has to be
   three. */
.mdl-reset {
  display: block; width: calc(100% - 10px); margin: 0 5px 1px;
  padding: 7px 5px; border: 0; border-radius: 7px; background: transparent;
  font-size: 11.5px; color: var(--ink-4); text-align: left; cursor: pointer;
  transition: color .12s ease, background-color .12s ease;
}
.mdl-reset:hover { background: var(--hover); color: var(--ink-2); }
.mdl-reset[hidden] { display: none; }

/* The turn tag — only under a turn that ran off-default. Sits with the
   whispers and the source pills, in the same mono voice. */
.mdl-tag {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: -4px; padding-left: 2px;
  font-family: var(--mono); font-size: 9px; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
}

/* Phone: the chip grows to a thumb's worth of height, and the popover stops
   at the viewport rather than its natural 288px. */
@media (max-width: 560px) {
  .mdl-btn { height: 34px; padding: 0 10px; }
  .mdl-pop { width: min(288px, calc(100vw - 32px)); }
}

@media (prefers-reduced-motion: reduce) {
  .mdl-btn { transition: none; }
  .mdl-wrap.open .mdl-pop { animation: none; }
}

/* ============ DARK MODE overrides (tokens flip in design.css) ============ */
[data-theme="dark"] body[data-themeable] .cop-ledger {
  --cop-ok-edge: oklch(0.40 0.05 160);
  --cop-bad-edge: oklch(0.42 0.06 25);
}
[data-theme="dark"] body[data-themeable] .cop-confirm { border-color: #5A4A28; }
[data-theme="dark"] body[data-themeable] .cop-chip-error {
  background: oklch(0.27 0.04 25); border-color: oklch(0.42 0.06 25);
  color: oklch(0.80 0.08 25);
}
[data-theme="dark"] body[data-themeable] .cop-chip-thumb,
[data-theme="dark"] body[data-themeable] .cop-file-thumb {
  outline-color: rgba(255, 255, 255, 0.12);
}
