/* HERMES WEB DECK — dark terminal aesthetic */
:root {
  --bg: #0a0e12;
  --bg2: #0e141a;
  --bg3: #131b23;
  --line: #1d2833;
  --fg: #c9d7e2;
  --dim: #93a9bc;
  --dimmer: #64798c;
  --cyan: #38e1d4;
  --amber: #f5b942;
  --violet: #a78bfa;
  --red: #f4564e;
  --green: #3ce88a;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --sans: var(--mono);
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
/* HARD SCROLL LOCK (2026-07-22): the document itself must NEVER scroll —
   only inner containers (.transcript, .cards, modals) scroll. overflow:hidden
   alone is ignored by iOS Safari (rubber-banding + the focus-scroll hijack
   that shoved the composer off the top of the screen); position:fixed on
   body is the only reliable kill. The app shell sizes itself via --vvh. */
html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }
body {
  background: var(--bg); color: var(--fg);
  font-family: var(--sans); font-size: 14px;
  position: fixed; inset: 0; width: 100%;
  touch-action: manipulation;
}
/* inner scrollers contain their own overscroll — a flick at the end of a
   scroll never leaks to the shell and rubber-bands the whole interface */
.cards, .transcript, .model-list, .spells-list, .modal-body-view, .bay-items, .lw-prog {
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.transcript, .cards { touch-action: pan-y; }
.hidden { display: none !important; }
button { font-family: inherit; cursor: pointer; }

/* ---------- LOGIN ---------- */
.login {
  position: fixed; inset: 0; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at 50% 30%, #0d1620 0%, var(--bg) 70%);
  z-index: 100;
}
.login-box { width: min(360px, 88vw); display: flex; flex-direction: column; gap: 14px; }
.login-logo { font-size: 20px; letter-spacing: 3px; color: var(--fg); text-align: center; }
.login-logo span { color: var(--cyan); }
.login-sub { color: var(--dim); font-size: 12.5px; text-align: center; letter-spacing: 1px; }
.login-box input {
  background: var(--bg2); border: 1px solid var(--line); color: var(--cyan);
  padding: 13px 14px; border-radius: 6px; font-family: var(--mono); font-size: 16px;
  outline: none; letter-spacing: 1px;
}
.login-box input:focus { border-color: var(--cyan); box-shadow: 0 0 0 1px rgba(56,225,212,.25); }
.login-box button {
  background: rgba(56,225,212,.12); border: 1px solid var(--cyan); color: var(--cyan);
  padding: 12px; border-radius: 6px; letter-spacing: 2px; font-size: 13px; min-height: 44px;
}
.login-box button:hover { background: rgba(56,225,212,.22); }
.login-err { color: var(--red); font-size: 12px; text-align: center; min-height: 16px; }

/* ---------- SHELL ---------- */
.app { display: flex; height: 100dvh; height: var(--vvh, 100dvh); }
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; position: relative; overflow-x: hidden; }

/* ---------- SIDEBAR ---------- */
.sidebar {
  width: 300px; flex-shrink: 0; background: var(--bg2);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  transition: margin-left .22s ease, transform .22s ease;
  padding-top: env(safe-area-inset-top);
}
.app.collapsed .sidebar { margin-left: -300px; }
.sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 12px 10px 16px;
}
.brand { letter-spacing: 3px; font-size: 13px; color: var(--dim); }
.icon-btn {
  background: transparent; border: 1px solid var(--line); color: var(--dim);
  border-radius: 6px; min-width: 34px; min-height: 34px; font-size: 13px;
}
.icon-btn:hover { color: var(--cyan); border-color: var(--cyan); }
.icon-btn.small { min-width: 28px; min-height: 28px; }
/* the pinned ✦ NEW card (his #7, 2026-08-11): the ONLY "add instance" —
   constant, always top of the hamburgers, tap = spin up a worker.
   (.card.card-new — the two-class specificity beats .card's grid display) */
.card.card-new {
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--cyan); background: rgba(56,225,212,.06);
  cursor: pointer; min-height: 52px; padding: 10px;
}
.card.card-new:hover { background: rgba(56,225,212,.14); border-color: var(--cyan); }
.card-new-inner {
  font-family: var(--mono); font-size: 13px; letter-spacing: 2px; color: var(--cyan);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.card-new-sub { font-size: 9.5px; letter-spacing: 1px; color: var(--dimmer); }
/* per-card model line (his #4, 2026-08-11): every hamburger says its model */
.card-model { font-family: var(--mono); font-size: 10px; letter-spacing: 1px; color: var(--dim); }
.card-model.nomodel { color: var(--red); animation: pulse-amber 1.4s ease-in-out infinite; }
.cards { flex: 1; overflow-y: auto; padding: 0 10px 10px; display: flex; flex-direction: column; gap: 8px; }
.sidebar-foot {
  border-top: 1px solid var(--line); padding: 10px 14px;
  display: flex; align-items: center; justify-content: space-between; font-size: 12.5px;
  padding-bottom: calc(10px + env(safe-area-inset-bottom));
}
.conn-state { letter-spacing: 2px; }
.conn-state.on { color: var(--green); }
.conn-state.off { color: var(--red); }

/* ---------- INSTANCE CARDS ---------- */
.card {
  background: var(--bg3); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px; cursor: pointer; position: relative; user-select: none;
  display: grid; grid-template-columns: 40px 1fr; gap: 4px 10px;
}
.card:hover { border-color: var(--dimmer); }
.card.active { border-color: var(--cyan); background: #12222a; }
.card.flash { animation: cardflash 1.6s ease-out; }
@keyframes cardflash {
  0% { box-shadow: 0 0 0 2px var(--cyan), 0 0 24px rgba(56,225,212,.7); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.card-avatar {
  grid-row: auto; width: 40px; height: 40px; border-radius: 50%;
  background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; color: #061014; font-weight: 700;
}
.card-top { display: flex; align-items: center; gap: 7px; min-width: 0; }
.card-name {
  flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 13px; color: var(--fg);
}
.card-time { font-size: 12px; color: var(--dimmer); flex-shrink: 0; }
.badge-link {
  font-size: 12.5px; color: var(--cyan); border: 1px solid var(--cyan); border-radius: 3px;
  padding: 0 4px; letter-spacing: 1px; flex-shrink: 0;
}
.dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; background: var(--dimmer); }
/* 2026-07-30 (his call): WORKING = VIOLET. It used to share green with
   DONE/finished — indistinguishable in the hamburger. Green is finished-only
   now. pulse keyframe stays green (conn-dot.off reuses it), hence the
   dedicated violet keyframe. */
.dot.working { background: var(--violet); animation: pulse-violet 1.2s ease-in-out infinite; }
/* 2026-08-08 (his #5): NEEDS APPROVAL gets the HOT amber — more vibrant than
   anything else on the board, with a real glow */
.dot.awaiting_approval { background: #ffbe0b; box-shadow: 0 0 7px rgba(255,190,11,.9); animation: pulse-amber .7s ease-in-out infinite; }
.dot.error { background: var(--red); }
/* 2026-08-08 (his #14): IDLE = GREEN. Blue is dead. */
.dot.idle { background: var(--green); }
/* 2026-08-08 (his #5): idle-on-a-question = half amber / half green split
   dot with a dotted ring — "idling, but on a question" */
.dot.waiting {
  background: linear-gradient(135deg, #ffbe0b 50%, var(--green) 50%);
  outline: 1.5px dotted rgba(255,190,11,.8); outline-offset: 1px;
  animation: pulse-amber 1.4s ease-in-out infinite;
}
/* 2026-07-31 (his ask): a THIRD hamburger state — brand-new session (after
   /new, before the first prompt) reads CYAN, never dead-idle gray */
.dot.fresh { background: var(--cyan); animation: pulse-cyan 1.6s ease-in-out infinite; }
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(60,232,138,.6); opacity: 1; }
  50% { box-shadow: 0 0 0 5px rgba(60,232,138,0); opacity: .65; }
}
@keyframes pulse-violet {
  0%,100% { box-shadow: 0 0 0 0 rgba(167,139,250,.6); opacity: 1; }
  50% { box-shadow: 0 0 0 5px rgba(167,139,250,0); opacity: .65; }
}
@keyframes pulse-cyan {
  0%,100% { box-shadow: 0 0 0 0 rgba(56,225,212,.55); opacity: 1; }
  50% { box-shadow: 0 0 0 5px rgba(56,225,212,0); opacity: .7; }
}
/* ✎ *draft* marker on hamburger cards (2026-07-31) — unsent composer text
   sitting in that instance, synced across devices */
.card-draft {
  color: var(--amber); font-style: italic; font-size: 11.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@keyframes pulse-amber {
  0%,100% { box-shadow: 0 0 0 0 rgba(245,185,66,.7); opacity: 1; }
  50% { box-shadow: 0 0 0 6px rgba(245,185,66,0); opacity: .55; }
}
/* batch 13 (his "the goal should get the majority"): the card's text lines
   span the FULL card width — no more skinny column beside the avatar where
   the ghost/goal wrapped a word per line. Avatar rides the top row only. */
.card-lines { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.card-goal, .card-subtask, .card-snippet, .card-subname {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12.5px;
}
.card-goal .lbl, .card-subtask .lbl {
  font-size: 8.5px; letter-spacing: 1.5px; color: var(--dimmer); margin-right: 5px;
}
/* HERO GOAL — its own full-width line under the name row (2026-07-22: used to
   share the top row with the status word, which squeezed it into a tall thin
   column on "NEEDS APPROVAL"). Never competes for width again. */
.card-hero {
  display: block; width: 100%; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 12.5px; letter-spacing: .5px; color: var(--green);
  border: 1px solid rgba(60,232,138,.55); border-radius: 4px;
  padding: 1px 7px; background: rgba(60,232,138,.07);
}
/* 2026-08-04 (his #1): the working-state hero recolor is DEAD — the hero now
   wears a per-instance hue from goalColorFor() via inline style. Every card
   its own color, none of the all-green/all-cyan soup. */
.card-lock {
  color: var(--violet); font-size: 11px; letter-spacing: 1px;
  border: 1px solid rgba(167,139,250,.5); background: rgba(167,139,250,.09);
  border-radius: 4px; padding: 1px 7px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.is-locked { color: var(--violet); }
.card-subname { color: var(--dim); font-size: 12px; letter-spacing: 1px; }
.card-goal { color: var(--dim); }
.card-subtask { color: var(--dimmer); }
.card.working .card-subtask { color: var(--cyan); }
.card.working .card-subtask .lbl { color: rgba(56,225,212,.6); }
.card-snippet { color: var(--dimmer); font-style: italic; }
/* expand affordance: ▾ tap on phone (#20 — big boxed target), hard-lock on
   desktop (#18 — hover stays a temporary peek, ▾ pins it open) */
.card-expand {
  background: var(--bg2); border: 1px solid var(--line); color: var(--dimmer);
  font-size: 14px; border-radius: 6px;
  min-width: 34px; min-height: 34px; flex-shrink: 0;
}
.card-expand:hover { color: var(--cyan); border-color: var(--cyan); }
.card.expanded .card-expand { transform: rotate(180deg); color: var(--cyan); border-color: var(--cyan); }
@media (max-width: 899px) {
  .card-expand { min-width: 44px; min-height: 44px; font-size: 17px; }
}
/* status pill (#17): dot + word, clickable → toggles the card open (#18) */
.card-statuspill {
  display: flex; align-items: center; gap: 5px; flex-shrink: 0;
  background: none; border: none; padding: 2px 0; min-height: 28px;
}
.card-st { font-size: 8.5px; letter-spacing: 1px; color: var(--dimmer); }
.card-statuspill.working .card-st { color: var(--violet); }
/* 2026-08-08 (his #5): the act-now word glows in hot amber */
.card-statuspill.awaiting_approval .card-st { color: #ffbe0b; text-shadow: 0 0 7px rgba(255,190,11,.55); animation: pulse-amber .9s ease-in-out infinite; }
.card-statuspill.awaiting_response .card-st { color: var(--green); animation: pulse-amber .9s ease-in-out infinite; }
.card-statuspill.error .card-st { color: var(--red); }
/* 2026-08-08 (his #14): idle goes green */
.card-statuspill.idle .card-st { color: var(--green); }
/* 2026-08-08 (his #5): waiting-on-a-question wears a dotted amber frame */
.card-statuspill.waiting { border: 1px dotted rgba(255,190,11,.75); border-radius: 6px; padding: 2px 7px; }
.card-statuspill.waiting .card-st { color: #ffbe0b; }
.card-statuspill.done .card-st { color: var(--green); }
.card-statuspill.fresh .card-st { color: var(--cyan); }
/* READY (his #8, 2026-08-04): a fresh session must SCREAM "click me, I'm
   loaded" — boxed pill, fat letterspaced word, card border glows cyan. The
   old bare dot was so quiet he never even noticed it existed. */
.card-statuspill.fresh {
  border: 1px solid var(--cyan); border-radius: 6px;
  padding: 2px 7px; background: rgba(56,225,212,.14);
  animation: pulse-cyan 1.4s ease-in-out infinite;
}
.card-statuspill.fresh .card-st { font-size: 10px; font-weight: 700; letter-spacing: 1.5px; }
.card.fresh { border-color: rgba(56,225,212,.55); box-shadow: 0 0 14px rgba(56,225,212,.10); }
.dot.awaiting_response { background: var(--green); animation: pulse-amber .9s ease-in-out infinite; }
/* see more… — hidden until the card is opened (hover / ▾), link-style */
.card-prompt-btn {
  display: none; align-self: flex-start; margin-top: 2px;
  background: none; border: none; color: var(--cyan);
  font-size: 12px; letter-spacing: 1px; padding: 2px 0; min-height: 26px;
  text-decoration: underline; text-underline-offset: 3px;
}
.card-prompt-btn:hover { color: #7ff0e6; }
@media (min-width: 900px) {
  /* desktop: hover un-clamps goal/subtask/name; snippet gets a 3-line clamp
     so a monster prompt can't blow the card up — full text via the button */
  .card:hover .card-hero, .card.active .card-hero,
  .card:hover .card-subtask, .card:hover .card-subname {
    white-space: normal; overflow: visible; word-break: break-word;
  }
  .card:hover .card-snippet {
    white-space: normal; word-break: break-word;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .card:hover { padding: 12px 10px; }           /* a little more chunk */
  .card:hover .card-prompt-btn { display: inline-block; }
}
@media (max-width: 899px) {
  .card-expand { display: block; }
  .card.expanded .card-expand { transform: rotate(180deg); color: var(--cyan); }
  .card.expanded .card-hero, .card.expanded .card-subtask, .card.expanded .card-subname {
    white-space: normal; overflow: visible; word-break: break-word;
  }
  /* phone: snippet clamps to 3 lines even when expanded — big prompts open
     in the ORIGINAL PROMPT viewer instead of swallowing the drawer */
  .card.expanded .card-snippet {
    white-space: normal; word-break: break-word;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .card.expanded .card-prompt-btn { display: inline-block; min-height: 32px; }
}

/* ---------- TOPBAR / HEADER ---------- */
.topbar {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--line); background: var(--bg2); min-height: 58px;
  padding-top: calc(10px + env(safe-area-inset-top));
}
.hamburger { display: none; flex-direction: column; justify-content: center; gap: 4px; align-items: center; min-width: 44px; min-height: 44px; }
.hamburger span { display: block; width: 18px; height: 2px; background: var(--dim); }
.expand-btn { flex-shrink: 0; }
.hdr { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; }
.hdr-avatar {
  width: 40px; height: 40px; border-radius: 50%; cursor: pointer; flex-shrink: 0;
  background-size: cover; background-position: center;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; color: #061014; font-weight: 700;
  border: 1px solid var(--line);
}
.hdr-avatar:hover { border-color: var(--cyan); }
.hdr-meta { min-width: 0; flex: 1; }
.hdr-name { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hdr-sub { font-size: 12.5px; color: var(--dim); display: flex; gap: 12px; }
/* his #4 (2026-08-11 — "I want the model back from the top"): the topbar
   model chip. Tap = switch. Red + blinking while no model is pinned (#5). */
.model-chip {
  flex-shrink: 0; max-width: 34%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--mono); font-size: 11px; letter-spacing: 1px;
  color: var(--cyan); background: rgba(56,225,212,.07); border: 1px solid rgba(56,225,212,.45);
  border-radius: 999px; padding: 5px 10px; min-height: 30px;
}
.model-chip:hover { background: rgba(56,225,212,.16); }
.model-chip.locked { color: var(--violet); border-color: rgba(167,139,250,.5); background: rgba(167,139,250,.07); }
.model-chip.nomodel { color: var(--red); border-color: rgba(244,86,78,.6); background: rgba(244,86,78,.08); animation: pulse-amber 1.4s ease-in-out infinite; }
#hdr-status.working { color: var(--violet); }
#hdr-status.awaiting_approval { color: var(--amber); }
#hdr-status.error { color: var(--red); }

/* ---------- EMPTY STATE ---------- */
.empty-state {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; color: var(--dimmer); font-size: 13px; letter-spacing: 1px;
}
.empty-logo { font-size: 42px; color: var(--line); }

/* ---------- TRANSCRIPT ---------- */
.transcript-wrap { flex: 1; position: relative; min-height: 0; }
.wallpaper {
  position: absolute; inset: 0; background-size: cover; background-position: center;
  z-index: 0;
}
.wallpaper::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(0,0,0,.72); backdrop-filter: blur(2px);
}
/* RANK IDENTITY (his riff 2026-08-11): rank = initiation order, and the rank
   owns the color + face + wallpaper. Set in stone — pure function of rec.n. */
.wallpaper.rankwp::after { background: rgba(0,0,0,.5); backdrop-filter: none; }
.card.ranked { box-shadow: inset 3px 0 0 var(--rank); }   /* accent without layout shift */
.card-avatar.rankface, .hdr-avatar.rankface { font-size: 19px; font-weight: 400; }
.transcript {
  position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden; z-index: 1;
  padding: 18px 16px 24px; display: flex; flex-direction: column; gap: 10px;
  scroll-behavior: auto;   /* #10: snappy — jumps are instant, not animated */
}
/* hard containment (2026-07-22): a long unbroken string (rugcheck URL inside a
   halted approval) once blew out of its card and made the whole page scroll
   sideways forever. Nothing inside the transcript may ever set its width. */
.msg, .approval, .clarify, .sysline, .msg-text { min-width: 0; }
.msg { max-width: min(720px, 86%); border-radius: 10px; padding: 9px 13px; font-size: 13.5px;
  line-height: 1.55; white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; }
.msg .tags { display: flex; gap: 6px; margin-bottom: 4px; }
.tag {
  font-size: 12.5px; letter-spacing: 1.5px; padding: 1px 6px; border-radius: 3px;
  border: 1px solid currentColor;
}
.msg.bot {
  align-self: flex-start; font-family: var(--mono);
  background: rgba(19,27,35,.88); border: 1px solid var(--line); color: var(--fg);
}
.msg.user-regular {
  align-self: flex-end; background: rgba(56,225,212,.08);
  border: 1px solid rgba(56,225,212,.45); color: #bff5ef;
}
.msg.user-regular .tag { color: var(--cyan); }
.msg.user-steer {
  align-self: flex-end; margin-right: 8%;
  background: rgba(245,185,66,.08); border: 1px solid rgba(245,185,66,.55); color: #fadfa8;
}
.msg.user-steer .tag { color: var(--amber); }
.msg.user-queue {
  align-self: flex-end; background: rgba(167,139,250,.07);
  border: 1.5px dashed rgba(167,139,250,.6); color: #d4c6fd;
}
.msg.user-queue .tag { color: var(--violet); }
.tag.interrupt { color: var(--red) !important; }
.tag.effort { color: var(--dim) !important; border-color: var(--dimmer); }
.sysline {
  align-self: center; text-align: center; color: var(--amber); font-size: 12.5px;
  max-width: 90%;
}
.divider {
  align-self: stretch; display: flex; align-items: center; gap: 10px;
  color: var(--cyan); font-size: 12px; letter-spacing: 2px; margin: 6px 0;
}
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.capsule {
  align-self: center; border: 1px solid var(--violet); color: var(--violet);
  border-radius: 999px; padding: 3px 14px; font-size: 12px; letter-spacing: 2px;
}
.approval {
  align-self: center; width: min(560px, 92%); border: 1px solid var(--amber);
  border-radius: 10px; padding: 10px 14px; background: rgba(245,185,66,.06); font-size: 12px;
}
.approval .ap-head { color: var(--amber); letter-spacing: 2px; font-size: 12px; margin-bottom: 6px; }
.approval code { font-family: var(--mono); color: var(--fg); word-break: break-all; overflow-wrap: anywhere; }
.approval.approved { border-color: var(--green); } .approval.approved .ap-head { color: var(--green); }
.approval.denied, .approval.halted { border-color: var(--red); opacity: .75; }
.approval.denied .ap-head, .approval.halted .ap-head { color: var(--red); }
.jump-pill {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%); z-index: 2;
  background: var(--bg3); border: 1px solid var(--cyan); color: var(--cyan);
  border-radius: 999px; padding: 8px 18px; font-size: 12.5px; letter-spacing: 1px;
  box-shadow: 0 4px 18px rgba(0,0,0,.5);
}

/* ---------- COMPOSER ---------- */
.composer {
  border-top: 1px solid var(--line); background: var(--bg2); padding: 8px 12px;
  padding-bottom: calc(8px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 8px;
}
/* keyboard open (2026-07-23): the home-indicator inset is covered by the
   keyboard, so the safe-area padding is pure dead zone — reclaim it. */
body.kb-open .composer { padding-bottom: 6px; }
.composer-row { display: flex; align-items: center; gap: 8px; }
.composer-row.modes { flex-wrap: wrap; row-gap: 6px; }
/* no .spacer (2026-07-22): it shoved effort/NEW/MODEL to the far right with a
   dead gap — "space on its left with nothing on it". Everything flows left. */
@media (max-width: 899px) {
  .composer-row.modes { gap: 6px; }
  .composer-row.modes .chip, .composer-row.modes .effort-sel { padding-left: 10px; padding-right: 10px; }
}
/* two explicit rows, each horizontally scrollable (2026-07-22): instead of
   flex-wrap luck, row 1 = mode chips, row 2 = actions — and if either row
   over-extends the border on any screen it SCROLLS sideways instead of
   clipping or wrapping ragged. Scrollbars hidden; swipe still works. */
.composer-row.scroll-x {
  flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.composer-row.scroll-x::-webkit-scrollbar { display: none; }
.composer-row.scroll-x > * { flex-shrink: 0; }
.chip {
  background: transparent; border: 1px solid var(--line); color: var(--dim);
  border-radius: 999px; padding: 6px 14px; font-size: 13px; letter-spacing: 1.5px;
  min-height: 32px;
}
.chip:disabled { opacity: .32; cursor: not-allowed; }
.mode-chip.active[data-mode="regular"] { color: var(--cyan); border-color: var(--cyan); background: rgba(56,225,212,.1); }
.mode-chip.active[data-mode="steer"] { color: var(--amber); border-color: var(--amber); background: rgba(245,185,66,.1); }
.mode-chip.active[data-mode="queue"] { color: var(--violet); border-color: var(--violet); background: rgba(167,139,250,.1); }
.mode-chip.active[data-mode="pg"] { color: var(--green); border-color: var(--green); background: rgba(60,232,138,.1); }
.effort-sel {
  background: var(--bg3); border: 1px solid var(--line); color: var(--dim);
  border-radius: 6px; padding: 6px 8px; font-family: var(--mono); font-size: 12.5px;
  min-height: 32px; outline: none;
}
.stop-btn { color: var(--red); border-color: var(--red); background: rgba(244,86,78,.08); }
.stop-btn:hover:not(:disabled) { background: rgba(244,86,78,.2); }
/* batch-13 composer grid (his circled-grey-gap report): the rail lives BESIDE
   the whole left stack (chips1 / chips2 / textarea), stretches the full
   composer height, and its buttons spread evenly — "slide in nice and
   perfectly". The chips now hug the textarea directly left of the rail; the
   grey void between the buttons and the box is structurally impossible. */
.composer-body { display: flex; gap: 8px; align-items: stretch; }
.composer-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; justify-content: flex-end; }
.input-row { align-items: stretch; }
.input-row #input { width: 100%; }
.rail { align-self: stretch; justify-content: flex-start; }
.rail .rail-btn, .rail .send-btn { flex: 1 1 0; height: auto; min-height: 30px; width: 38px; }
.rail .send-btn { flex: 1.35 1 0; min-height: 40px; }   /* thumb anchor, slightly fatter */
#input {
  flex: 1; resize: none; background: var(--bg3); border: 1px solid var(--line);
  color: var(--fg); border-radius: 10px; padding: 11px 13px; font-family: var(--mono);
  font-size: 16px; line-height: 1.4; outline: none; max-height: 180px; min-height: 44px;
}
#input:focus { border-color: var(--mode-color, var(--cyan)); }
.send-btn {
  width: 44px; height: 44px; border-radius: 10px; flex-shrink: 0;
  background: rgba(56,225,212,.12); border: 1px solid var(--cyan); color: var(--cyan);
  font-size: 16px;
}
.send-btn:disabled { opacity: .35; }
.composer.mode-steer .send-btn { border-color: var(--amber); color: var(--amber); background: rgba(245,185,66,.1); }
.composer.mode-queue .send-btn { border-color: var(--violet); color: var(--violet); background: rgba(167,139,250,.1); }
.composer.mode-pg .send-btn { border-color: var(--green); color: var(--green); background: rgba(60,232,138,.1); }

/* ---------- CONTEXT MENU / MODAL ---------- */
.ctx-menu {
  position: fixed; z-index: 60; background: var(--bg3); border: 1px solid var(--line);
  border-radius: 8px; overflow: hidden; min-width: 150px;
  box-shadow: 0 8px 30px rgba(0,0,0,.6);
}
.ctx-menu button {
  display: block; width: 100%; text-align: left; background: none; border: none;
  color: var(--fg); padding: 12px 16px; font-size: 13px; min-height: 44px;
}
.ctx-menu button:hover { background: var(--bg2); }
.ctx-menu button.danger { color: var(--red); }
.modal {
  /* 2026-08-08 (his #2-4): was z-index 70 — UNDER the editor overlay (92) and
     the lightbox (95), so the CLEAR-Draft confirm materialized BEHIND the big
     editor ("the clear button makes the confirm appear behind the text box").
     The modal is the topmost interactive layer, always. */
  position: fixed; inset: 0; z-index: 120; background: rgba(0,0,0,.6);
  display: flex; align-items: center; justify-content: center;
}
.modal-box {
  width: min(400px, 90vw); background: var(--bg2); border: 1px solid var(--line);
  border-radius: 12px; padding: 20px; display: flex; flex-direction: column; gap: 12px;
}
.modal-title { letter-spacing: 2px; font-size: 13px; color: var(--fg); display: flex; align-items: center; justify-content: space-between; }
.modal-x {
  background: none; border: 1px solid var(--line); color: var(--dim);
  border-radius: 6px; min-width: 32px; min-height: 32px; font-size: 13px;
}
.modal-x:hover { color: var(--red); border-color: var(--red); }
.modal-body { color: var(--dim); font-size: 12.5px; line-height: 1.5; }
/* #10 (2026-07-23): settings/confirm bodies must SCROLL — expanded lists
   (per-instance notifications, don't-ask-again resets) run past the screen
   with no way to reach the bottom. Cap the box, scroll the body. */
.modal-box { max-height: 88dvh; }
.modal-body {
  max-height: 62dvh; overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch; touch-action: pan-y;
}
/* read-only viewer (ORIGINAL PROMPT): scrollable, selectable, monospace */
.modal-body-view {
  max-height: 55dvh; overflow-y: auto; white-space: pre-wrap; word-break: break-word;
  font-family: var(--mono); font-size: 13px; color: var(--fg);
  background: var(--bg3); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; -webkit-user-select: text; user-select: text;
}
/* sectioned details viewer (see more…) */
.mv-sec { margin-bottom: 12px; }
.mv-sec:last-child { margin-bottom: 0; }
.mv-lbl {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; letter-spacing: 2px; color: var(--cyan);
  border-bottom: 1px solid var(--line); padding-bottom: 3px; margin-bottom: 5px;
}
.mv-text { white-space: pre-wrap; word-break: break-word; color: var(--fg); }
.mv-text.clamped {
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}
.mv-more {
  background: none; border: none; color: var(--cyan); font-size: 12px;
  padding: 3px 0; letter-spacing: 1px; text-decoration: underline;
  text-underline-offset: 3px; min-height: 26px;
}
.mv-copy { position: static; opacity: .8; }   /* override .copy-btn absolute */
.modal-input {
  background: var(--bg3); border: 1px solid var(--line); color: var(--fg);
  padding: 10px 12px; border-radius: 6px; font-family: var(--mono); outline: none;
}
.modal-input:focus { border-color: var(--cyan); }
.modal-btns { display: flex; gap: 10px; justify-content: flex-end; }
.modal-btns button {
  background: transparent; border: 1px solid var(--line); color: var(--dim);
  border-radius: 6px; padding: 9px 18px; font-size: 12px; letter-spacing: 1px; min-height: 40px;
}
.modal-btns button.danger { color: var(--red); border-color: var(--red); }
.modal-btns button.primary { color: var(--cyan); border-color: var(--cyan); }

/* ---------- MOBILE ---------- */
.drawer-backdrop {
  display: none; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 40;
}
@media (max-width: 899px) {
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; z-index: 50;
    transform: translateX(-105%); margin-left: 0 !important;
    width: min(320px, 85vw); box-shadow: 8px 0 40px rgba(0,0,0,.6);
  }
  .app.drawer-open .sidebar { transform: translateX(0); }
  .app.drawer-open .drawer-backdrop { display: block; }
  .hamburger { display: flex; }
  #collapse-btn, .expand-btn { display: none !important; }
  .msg { max-width: 92%; }
}
@media (min-width: 900px) {
  .hamburger { display: none; }
}

/* scrollbars */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; }
::-webkit-scrollbar-track { background: transparent; }

/* ---------- HOLDING BAYS (Phase 3) ---------- */
.bay { border-radius: 10px; padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; }
.bay-head { display: flex; align-items: center; justify-content: space-between; }
.bay-title { font-size: 12.5px; letter-spacing: 2px; }
.bay-clear {
  background: none; border: none; color: var(--dim); font-size: 12px;
  letter-spacing: 1px; text-decoration: underline; padding: 2px 4px;
}
.bay-items { display: flex; flex-direction: column; gap: 5px; }
.bay-item {
  display: flex; align-items: center; gap: 8px; font-size: 12px;
  background: rgba(0,0,0,.25); border-radius: 6px; padding: 6px 8px;
}
.bay-item .bi-idx { font-size: 12.5px; color: var(--dimmer); flex-shrink: 0; }
.bay-item .bi-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bay-item .bi-effort {
  font-size: 8.5px; letter-spacing: 1px; border: 1px solid var(--dimmer); color: var(--dim);
  border-radius: 3px; padding: 0 4px; flex-shrink: 0;
}
.bay-item .bi-x {
  background: none; border: none; color: var(--dim); font-size: 13px;
  min-width: 26px; min-height: 26px; flex-shrink: 0;
}
.bay-item .bi-x:hover { color: var(--red); }
.bay-item .bi-fire {
  background: rgba(167,139,250,.15); border: 1px solid var(--violet); color: var(--violet);
  border-radius: 5px; padding: 3px 10px; font-size: 12px; letter-spacing: 1.5px; flex-shrink: 0;
}
.bay-item .bi-fire:hover:not(:disabled) { background: rgba(167,139,250,.3); }
.queue-bay { border: 1.5px dashed rgba(167,139,250,.55); background: rgba(167,139,250,.05); }
.queue-bay .bay-title { color: var(--violet); }
.queue-bay .bi-text { color: #d4c6fd; }
/* 2026-07-28: queue bay is dead — the idle-held queue rides this slim strip
   at the transcript end instead (his #4). Same violet family, one line. */
.qstrip {
  align-self: stretch; display: flex; align-items: center; gap: 8px;
  border: 1px dashed rgba(167,139,250,.55); background: rgba(167,139,250,.06);
  border-radius: 8px; padding: 6px 10px; margin-top: 4px;
  font-family: var(--mono); font-size: 11px; color: #d4c6fd;
}
.qstrip .qs-text {
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.qstrip button {
  flex-shrink: 0; font-family: var(--mono); font-size: 10px; letter-spacing: 1px;
  background: none; border: 1px solid rgba(167,139,250,.55); color: var(--violet);
  border-radius: 6px; padding: 3px 8px; cursor: pointer;
}
.qstrip button:disabled { opacity: .5; }
.steer-bay { border: 1px solid rgba(245,185,66,.55); background: rgba(245,185,66,.05); }
.steer-bay .bay-title { color: var(--amber); }
.steer-bay .bi-text { color: #fadfa8; }

/* ---------- SPELLS / MODEL ---------- */
.spell-btn { letter-spacing: 1px; color: var(--amber); border-color: rgba(245,185,66,.45); }
.spell-btn:disabled { color: var(--dim); border-color: var(--line); }
.spell-btn:not(:disabled):hover { color: var(--cyan); border-color: var(--cyan); }

/* ➕ spell drawer */
.plus-btn { font-size: 14px; padding-left: 10px; padding-right: 10px; }
.spells-sub { color: var(--dim); font-size: 12px; letter-spacing: 0; margin-left: 8px; font-weight: normal; }
.spells-list { max-height: 60dvh; }
/* height:auto + normal wrapping — .model-row's chrome assumes one-line rows;
   without these the two-line spell rows overlap on phone */
.spell-row {
  display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
  height: auto; min-height: 48px; white-space: normal; flex: none;
  padding-top: 10px; padding-bottom: 10px;
}
.spell-row .spell-name { color: var(--amber); letter-spacing: 1px; font-size: 13px; }
.spell-row .spell-desc { color: var(--dim); font-size: 12px; line-height: 1.4; text-align: left; }
.spell-row:hover .spell-name { color: var(--cyan); }
.tag.spell-tag { color: var(--amber); border-color: rgba(245,185,66,.55); }

/* drawer shelves: ✨ SPELLS (casts) / ⚙ SETTINGS (toggles) */
.shelf-head {
  color: var(--cyan); font-size: 12px; letter-spacing: 2px; font-weight: bold;
  padding: 10px 12px 4px; border-bottom: 1px solid rgba(90,200,250,.25);
  margin-bottom: 4px; user-select: none;
}
.tog-line { display: flex; align-items: center; justify-content: space-between; width: 100%; gap: 8px; }
.tog-pill {
  font-size: 12px; font-weight: bold; letter-spacing: 1px; padding: 2px 10px;
  border-radius: 10px; border: 1px solid; flex: none;
}
.tog-pill.off { color: var(--dim); border-color: rgba(147,169,188,.5); }
.tog-pill.on { color: #3ddc84; border-color: rgba(61,220,132,.7); background: rgba(61,220,132,.12); }
.tog-pill.on.armed {
  color: #ff5252; border-color: rgba(255,82,82,.85); background: rgba(255,82,82,.14);
  animation: armedPulse 1.6s ease-in-out infinite;
}
.toggle-row.danger .spell-name { color: #ff8a80; }
.toggle-row.danger.is-on { border-color: rgba(255,82,82,.6); background: rgba(255,82,82,.07); }
.toggle-row:disabled { opacity: .45; cursor: not-allowed; }
.toggle-row:disabled .spell-name { color: var(--dim); }
/* armed pulse HAS an off condition: it stops the moment the toggle goes OFF */
@keyframes armedPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,82,82,.5); }
  50% { box-shadow: 0 0 8px 2px rgba(255,82,82,.35); }
}
.status-box.yolo-armed {
  color: #ff5252; border-color: rgba(255,82,82,.85); background: rgba(255,82,82,.12);
  animation: armedPulse 1.6s ease-in-out infinite;
}

/* composer glow — bot is waiting on a typed answer. Off conditions: user
   starts typing, sends, or a new session starts (class removed in JS). */
.input-row.awaiting-response textarea {
  border-color: var(--green, #43e97b);
  box-shadow: 0 0 0 1px rgba(67,233,123,.35), 0 0 14px rgba(67,233,123,.25);
  animation: glowPulse 1.6s ease-in-out infinite;
}
@keyframes glowPulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(67,233,123,.35), 0 0 8px rgba(67,233,123,.18); }
  50%      { box-shadow: 0 0 0 1px rgba(67,233,123,.6),  0 0 18px rgba(67,233,123,.4); }
}
.input-row.awaiting-response textarea::placeholder {
  color: #43e97b; letter-spacing: 2px; font-weight: 600;
}

/* ---------- MODEL PICKER ---------- */
.model-box { max-height: 80dvh; }
.model-current { color: var(--cyan); font-size: 12.5px; letter-spacing: 0; margin-left: 8px; }
#model-search { font-size: 16px; }
.model-list { overflow-y: auto; max-height: 50dvh; display: flex; flex-direction: column; gap: 2px; }
.model-provider {
  font-size: 12.5px; letter-spacing: 2px; color: var(--dim); padding: 10px 4px 4px;
  border-bottom: 1px solid var(--line);
}
.model-row {
  background: none; border: 1px solid transparent; color: var(--fg); text-align: left;
  padding: 9px 10px; border-radius: 6px; font-family: var(--mono); font-size: 12.5px;
  min-height: 38px;
}
.model-row:hover { background: var(--bg3); border-color: var(--dimmer); }
.model-row.current { color: var(--cyan); border-color: var(--cyan); background: rgba(56,225,212,.08); }
.model-row.current::after { content: " ● current"; font-size: 12.5px; letter-spacing: 1px; }
.model-empty { color: var(--dimmer); font-size: 12.5px; text-align: center; padding: 14px; }
/* model favorites (★) */
.model-rowwrap { display: flex; align-items: stretch; gap: 2px; }
.model-rowwrap .model-row { flex: 1; }
.model-fav {
  background: none; border: none; color: var(--dimmer); font-size: 15px;
  min-width: 36px; border-radius: 6px; flex-shrink: 0;
}
.model-fav:hover { color: var(--amber); }
.model-fav.on { color: var(--amber); }
.model-provider.fav { color: var(--amber); border-bottom-color: rgba(245,185,66,.4); }

/* card prefs checklist */
.pref-note { color: var(--dim); font-size: 12px; margin-bottom: 8px; }
.pref-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 4px;
  font-size: 13px; color: var(--fg); cursor: pointer; min-height: 40px;
}
.pref-row input { width: 16px; height: 16px; accent-color: var(--cyan); }

/* live tool/runtime line on cards */
.card-live { font-size: 12px; color: var(--cyan); letter-spacing: .5px; }
.card-live .card-runtime { color: var(--dim); font-variant-numeric: tabular-nums; }
.hdr-runtime { opacity: .8; font-variant-numeric: tabular-nums; margin-left: 4px; }

/* ---------- APPROVAL BUTTONS ---------- */
.approval.pending { animation: appulse 1.4s ease-in-out infinite; }
@keyframes appulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(245,185,66,.35); }
  50% { box-shadow: 0 0 0 6px rgba(245,185,66,0); }
}
.ap-btns { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.ap-btns button {
  flex: 1 1 110px; border-radius: 6px; padding: 7px 6px; font-size: 12px; letter-spacing: 1.5px;
  min-height: 40px; background: transparent; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
}
.ap-btns .ap-sub { font-size: 8px; letter-spacing: 1px; opacity: .65; text-transform: lowercase; }
.ap-approve { border: 1px solid var(--green); color: var(--green); }
.ap-approve:hover:not(:disabled) { background: rgba(60,232,138,.15); }
.ap-deny { border: 1px solid var(--red); color: var(--red); }
.ap-deny:hover:not(:disabled) { background: rgba(244,86,78,.12); }
.ap-btns button:disabled { opacity: .4; cursor: wait; }
.ap-mark { margin-left: 6px; }
.badge-approval {
  font-size: 8.5px; color: var(--amber); border: 1px solid var(--amber); border-radius: 3px;
  padding: 0 4px; letter-spacing: 1px; flex-shrink: 0;
  animation: pulse-amber .7s ease-in-out infinite;
}

/* ---------- TOASTS ---------- */
.toasts {
  position: fixed; top: calc(10px + env(safe-area-inset-top)); left: 50%;
  transform: translateX(-50%); z-index: 90; display: flex; flex-direction: column;
  gap: 8px; align-items: center; pointer-events: none;
}
.toast {
  background: var(--bg3); border: 1px solid var(--line); color: var(--fg);
  border-radius: 999px; padding: 8px 18px; font-size: 12px; max-width: 86vw;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  box-shadow: 0 6px 24px rgba(0,0,0,.5); animation: toast-in .18s ease-out;
}
.toast.warn { border-color: var(--amber); color: var(--amber); }
.toast.err { border-color: var(--red); color: var(--red); }
@keyframes toast-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; } }
.toast.out { transition: opacity .3s; opacity: 0; }

/* ---------- CONN DOT (topbar) ---------- */
.conn-dot {
  width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; margin-left: auto;
}
.conn-dot.on { background: var(--green); }
.conn-dot.off { background: var(--red); animation: pulse 1s ease-in-out infinite; }

/* per-mode composer border tint */
.composer.mode-regular { border-top-color: rgba(56,225,212,.45); }
.composer.mode-steer { border-top-color: rgba(245,185,66,.55); }
.composer.mode-queue { border-top-color: rgba(167,139,250,.55); }
.composer.mode-pg { border-top-color: rgba(60,232,138,.55); }
.composer.mode-steer #input:focus { border-color: var(--amber); }
.composer.mode-queue #input:focus { border-color: var(--violet); }
.composer.mode-pg #input:focus { border-color: var(--green); }

/* ---------- COPY-CLEAN MESSAGES + COPY BUTTON (#2) ---------- */
/* meta chrome (tags, syslines, dividers, copy buttons) is unselectable, so a
   drag-select across the chat grabs ONLY message text — no subtext poops */
.noselect, .copy-btn, .divider, .capsule, .card, .bay, .topbar, .composer {
  -webkit-user-select: none; user-select: none;
}
.msg .msg-text { -webkit-user-select: text; user-select: text; }
.msg { position: relative; padding-right: 34px; }
.copy-btn {
  position: absolute; right: 4px; bottom: 4px; min-width: 28px; min-height: 28px;
  background: transparent; border: none; color: var(--dimmer); font-size: 13px;
  border-radius: 6px; opacity: .55;
}
.msg:hover .copy-btn { opacity: 1; color: var(--dim); }
.copy-btn.copied { color: var(--green); opacity: 1; }
.copy-btn.copyfail { color: var(--red); opacity: 1; }

/* ---------- EMOJI SIGNALS (#4) ---------- */
.sig { font-size: 12px; letter-spacing: 1px; border-radius: 3px; padding: 1px 6px; }
.sig-ask { color: var(--amber); border: 1px solid rgba(245,185,66,.55); background: rgba(245,185,66,.08); animation: pulse-amber 1.4s ease-in-out infinite; }
/* answered questions stop blinking and go quiet */
.sig-ask.answered { animation: none; opacity: .45; border-color: var(--line); color: var(--dim); background: transparent; }
.sig-fail { color: var(--red); }
.sig-ok { color: var(--green); }

/* ---------- DONE LINE + STATUS BOX (#5, #6) ---------- */
.done-line {
  color: var(--green); border: 1px solid rgba(60,232,138,.55); border-radius: 6px;
  padding: 4px 14px; letter-spacing: 2px; font-size: 12px; background: rgba(60,232,138,.06);
}
.status-box {
  display: inline-block; font-size: 12px; letter-spacing: 1.5px;
  border: 1px solid currentColor; border-radius: 4px; padding: 1px 8px;
}
.status-box.working {
  color: var(--green); background: rgba(60,232,138,.08);
  animation: statusglow 1.4s ease-in-out infinite;
}
@keyframes statusglow {
  0%,100% { box-shadow: 0 0 0 0 rgba(60,232,138,.45); }
  50% { box-shadow: 0 0 8px 1px rgba(60,232,138,.25); }
}
.status-box.approval { color: var(--amber); background: rgba(245,185,66,.08); animation: pulse-amber .9s ease-in-out infinite; }
.status-box.error { color: var(--red); background: rgba(244,86,78,.08); }
.status-box.done { color: var(--green); background: rgba(60,232,138,.06); }
.status-box.idle { color: var(--dim); border-color: var(--line); }

/* steer/queue chips in fallback mode (idle instance → regular send) (#3)
   — no opacity dim: user wants all idle chips the SAME brightness; dashed
   border on active is enough of a fallback hint */
.mode-chip.fallback.active { border-style: dashed; }

/* ---------------------------------------------------------------------------
   markdown rendering in bot messages (2026-07-20) — tables were pipe salad.
   Standing UI rules: nothing under 12px, bright over dim, color-coded. */
.msg-text.md .md-p { margin: 2px 0; }
.msg-text.md .md-gap { height: 8px; }
.msg-text.md .md-h { font-weight: 700; color: #7fd4ff; margin: 10px 0 4px; }
.msg-text.md .md-h1 { font-size: 17px; }
.msg-text.md .md-h2 { font-size: 15px; }
.msg-text.md .md-h3, .msg-text.md .md-h4 { font-size: 13.5px; }
.msg-text.md .md-list { margin: 4px 0 4px 20px; padding: 0; }
.msg-text.md .md-list li { margin: 2px 0; }
.msg-text.md .md-hr { border: 0; border-top: 1px solid #2d4356; margin: 8px 0; }
.msg-text.md .md-ic {
  background: #12212e; border: 1px solid #2d4356; border-radius: 4px;
  padding: 1px 5px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; color: #ffd479;
}
.msg-text.md .md-code {
  background: #0c1722; border: 1px solid #2d4356; border-radius: 8px;
  padding: 10px 12px; margin: 6px 0; max-width: 100%;
  overflow-x: hidden;                 /* never an inner sideways scroller… */
  white-space: pre-wrap;              /* …long lines WRAP instead (rugcheck incident) */
  word-break: break-all; overflow-wrap: anywhere;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; line-height: 1.5; color: #d7e7f5;
}
.msg-text.md .md-ic { overflow-wrap: anywhere; }
.msg-text.md .md-tbl td { overflow-wrap: anywhere; }
.msg-text.md a { color: #6ee7a8; text-decoration: underline; }
.msg-text.md strong { color: #ffffff; }
.msg-text.md .md-tblwrap { overflow-x: auto; margin: 8px 0; border-radius: 8px; }
.msg-text.md .md-tbl {
  border-collapse: collapse; width: 100%; font-size: 12.5px;
  background: #0c1722; border: 1px solid #2d4356;
}
.msg-text.md .md-tbl th {
  background: #16283a; color: #7fd4ff; font-weight: 700; text-align: left;
  padding: 7px 10px; border: 1px solid #2d4356; white-space: nowrap;
}
.msg-text.md .md-tbl td {
  padding: 6px 10px; border: 1px solid #223446;
  color: #d7e7f5; vertical-align: top;
}
.msg-text.md .md-tbl tbody tr:nth-child(even) { background: #101d2b; }

/* ---------- CONTEXT CHIP (#1) — always in the composer ---------- */
.ctx-chip {
  font-size: 12.5px; letter-spacing: 1px; color: var(--dim);
  border: 1px solid var(--line); border-radius: 6px; padding: 6px 10px;
  min-height: 32px; display: inline-flex; align-items: center;
  font-variant-numeric: tabular-nums; user-select: none;
}

/* ---------- CLARIFY CARD (#6) — approval family, green ---------- */
.clarify {
  align-self: center; width: min(560px, 92%); border: 1px solid var(--green);
  border-radius: 10px; padding: 10px 14px; background: rgba(60,232,138,.06);
  font-size: 12px;
}
.clarify.pending { animation: appulse-green 1.6s ease-in-out infinite; }
@keyframes appulse-green {
  0%,100% { box-shadow: 0 0 0 0 rgba(60,232,138,.35); }
  50% { box-shadow: 0 0 0 6px rgba(60,232,138,0); }
}
.clarify .cl-head { color: var(--green); letter-spacing: 2px; font-size: 12px; margin-bottom: 6px; }
.clarify .cl-q { color: var(--fg); font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.clarify .cl-mark { margin-left: 6px; }
.clarify.resolved { opacity: .8; }
.clarify.dead { border-color: var(--line); opacity: .55; }
.clarify.dead .cl-head { color: var(--dimmer); }
.cl-btns { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.cl-btns button {
  text-align: left; border-radius: 6px; padding: 9px 12px; font-size: 13px;
  min-height: 40px; background: transparent; border: 1px solid var(--green);
  color: var(--green); letter-spacing: .5px;
}
.cl-btns button:hover:not(:disabled) { background: rgba(60,232,138,.14); }
.cl-btns button:disabled { opacity: .4; cursor: wait; }
.cl-btns .cl-num {
  display: inline-block; min-width: 18px; font-size: 11px; color: var(--dim);
}
.cl-btns .cl-other { border-style: dashed; color: var(--dim); border-color: var(--dimmer); }
.cl-btns .cl-other:hover:not(:disabled) { color: var(--green); border-color: var(--green); }
.tag.clarify-tag { color: var(--green); border-color: rgba(60,232,138,.55); }
.status-box.ask {
  color: var(--green); background: rgba(60,232,138,.08);
  animation: statusglow 1.2s ease-in-out infinite;
}
.hdr-sub #hdr-status { cursor: pointer; }

/* ---------- TOOL CHROME (#12) — dim live activity line ---------- */
.toolline {
  color: var(--dimmer); font-size: 12px; letter-spacing: 1px;
  align-self: flex-start; opacity: .8;
}

/* ---------- PREFS modal action buttons (#13/#19) ---------- */
.pref-btn {
  display: block; width: 100%; text-align: left; margin-top: 6px;
  background: var(--bg3); border: 1px solid var(--line); color: var(--fg);
  border-radius: 6px; padding: 11px 12px; font-size: 12.5px; letter-spacing: 1px;
  min-height: 42px;
}
.pref-btn:hover { border-color: var(--cyan); color: var(--cyan); }
.noask-row { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 12px; }

/* ---------- CTX CHIP (2026-07-22) — context % lives IN the composer bar
   now (user rule: "I want it inside of the bar part of it"). Always visible
   while an instance is open; tabular numerals; amber ≥80%. */
.ctx-chip { font-variant-numeric: tabular-nums; letter-spacing: 1px; }
.ctx-chip.hot { color: var(--amber); border-color: var(--amber); }
.ctx-chip:hover { color: var(--cyan); border-color: var(--cyan); }

/* NEEDS-YOU pill (2026-07-22): a pending approval/clarify card that scrolls
   OUT OF VIEW leaves this pulsing pill behind — one tap jumps back to the
   card. */
.attn-pill {
  position: absolute; left: 12px; bottom: 16px; z-index: 3;
  background: rgba(19,27,35,.92); border: 1px solid var(--amber); color: var(--amber);
  border-radius: 999px; padding: 7px 14px; font-size: 12px; letter-spacing: 1px;
  box-shadow: 0 4px 18px rgba(0,0,0,.5); backdrop-filter: blur(3px);
  animation: appulse 1.4s ease-in-out infinite;
}
.attn-pill.clarify { border-color: var(--green); color: var(--green); animation: appulse-green 1.4s ease-in-out infinite; }

/* instance numbers + per-instance settings lists (2026-07-22) */
.card-num { color: var(--cyan); font-size: 11px; letter-spacing: 1px; flex-shrink: 0; opacity: .85; }
.mini-chip {
  background: var(--bg3); border: 1px solid var(--line); color: var(--dimmer);
  border-radius: 6px; padding: 4px 9px; font-size: 10.5px; letter-spacing: 1px;
  min-height: 26px;
}
.mini-chip.on { color: var(--green); border-color: var(--green); background: rgba(60,232,138,.08); }
.inst-row {
  display: flex; align-items: center; gap: 8px; padding: 8px 6px;
  border: 1px solid var(--line); border-radius: 8px; margin-top: 6px;
  background: var(--bg2);
}
.inst-row .ir-label { flex: 1; min-width: 0; font-size: 12px; color: var(--fg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.inst-row .ir-label .ir-goal { color: var(--dimmer); font-size: 11px; }
.inst-row .ir-reset { flex-shrink: 0; }
.inst-row .ir-reset:hover { color: var(--red); border-color: var(--red); }

/* ---------- BAR QUICK CHIPS (2026-07-22) — NEW + MODEL rescued from the ➕
   drawer back onto the composer bar (user rule). Compact so the row still
   fits on a phone next to STOP. */
.quick-chip { padding-left: 10px; padding-right: 10px; font-size: 12px; }
#new-btn { color: var(--amber); border-color: rgba(245,185,66,.45); }
#new-btn:hover:not(:disabled) { color: var(--red); border-color: var(--red); }
#model-btn:hover:not(:disabled) { color: var(--cyan); border-color: var(--cyan); }

/* ---------- LIVE WORK STREAM (2026-07-22) — ephemeral tool-progress bubble.
   Rides at the bottom of the transcript while a run is live; vanishes on
   completion. Never persisted. */
.livework {
  align-self: stretch; max-width: 100%;
  border: 1px solid rgba(56,225,212,.35); background: rgba(10,18,22,.85);
  border-radius: 10px; padding: 8px 12px; backdrop-filter: blur(2px);
  display: flex; flex-direction: column; gap: 6px; font-size: 12px;
}
.lw-head {
  color: var(--cyan); letter-spacing: 2px; font-size: 11px;
  display: flex; align-items: center; gap: 8px; user-select: none;
}
.lw-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  animation: pulse 1.2s ease-in-out infinite;
}
.lw-hb { color: var(--amber); letter-spacing: .5px; }
.lw-prog {
  font-family: var(--mono); white-space: pre-wrap; word-break: break-word;
  overflow-wrap: anywhere; color: var(--dimmer);
  max-height: 180px; overflow-y: auto;
  border-top: 1px dashed var(--line); padding-top: 6px;
}
.model-refresh { padding: 2px 4px 8px; font-size: 11px; letter-spacing: 1px; }

/* ---------- ATTACH / PHOTO (vision path) ---------- */
.attach-btn {
  width: 44px; height: 44px; border-radius: 10px; flex-shrink: 0;
  background: transparent; border: 1px solid var(--line); color: var(--dim);
  font-size: 17px;
}
.attach-btn:hover { color: var(--cyan); border-color: var(--cyan); }
.attach-btn.staged { color: var(--green); border-color: var(--green); background: rgba(60,232,138,.08); }
/* photo-strip DEAD 2026-08-11 (his #10) — staging is a green 📷✓, no popup */

/* VERTICAL ACTION RAIL (his #3, 2026-08-11): ⇗ / 📎 / 📷 / ➤ stacked on the
   side of the text box — "less like shit, better room for the rest of it".
   Rail wins over the legacy 44px squares it replaced. */
.rail { display: flex; flex-direction: column; gap: 5px; flex-shrink: 0; }
.rail .rail-btn {
  width: 38px; height: 34px; border-radius: 9px; flex-shrink: 0;
  background: transparent; border: 1px solid var(--line); color: var(--dim);
  font-size: 15px; line-height: 1; padding: 0;
}
.rail .rail-btn:hover { color: var(--cyan); border-color: var(--cyan); }
.rail .rail-btn.attach-btn.staged { color: var(--green); border-color: var(--green); background: rgba(60,232,138,.08); }
.rail .send-btn { width: 38px; height: 44px; }   /* thumb anchor rides the bottom */

/* ---------- 🕘 SESSION HISTORY (batch 13) ---------- */
.hist-list { max-height: 60dvh; }
.hist-row {
  display: flex; gap: 10px; align-items: center; width: 100%; text-align: left;
  padding: 10px 12px; margin-bottom: 8px; background: var(--bg3);
  border: 1px solid var(--line); border-radius: 10px; color: var(--fg);
  font-family: var(--mono); cursor: pointer;
}
.hist-row:hover { border-color: var(--cyan); }
.hist-live { color: var(--green, #3ce88a); font-size: 10px; font-weight: 700; flex-shrink: 0; }
.hist-dead { color: var(--dim); font-size: 11px; flex-shrink: 0; }
.hist-main { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.hist-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.hist-sub2 { color: var(--dim); font-size: 11px; }
.hist-go { color: var(--dim); flex-shrink: 0; }
.hist-view { max-height: 60dvh; overflow-y: auto; padding: 4px 2px; }
.hist-msg { margin: 6px 0; padding: 8px 10px; border-radius: 10px; font-size: 14px; overflow-wrap: break-word; }
.hist-msg.user { background: rgba(56,225,212,.08); border: 1px solid rgba(56,225,212,.25); }
.hist-msg.bot { background: var(--bg3); border: 1px solid var(--line); }
.hist-sys { color: var(--dim); font-size: 11px; margin: 4px 0; }
.hist-div { color: var(--cyan); text-align: center; font-size: 11px; letter-spacing: 2px; margin: 10px 0; }
.msg .msg-photo {
  display: block; max-width: min(260px, 100%); border-radius: 8px;
  border: 1px solid var(--line); margin-bottom: 6px; cursor: pointer;
}
.msg .msg-photo:hover { border-color: var(--cyan); }

/* ---------- 2026-07-23 UX BATCH 3 ---------- */
/* #9: the textarea scrolls INTERNALLY (pan-y) and never chains to the shell */
#input { overscroll-behavior: contain; touch-action: pan-y; }

/* #5: stale approval/question cards — closed, dim, buttonless */
.approval.expired, .clarify.expired { border-color: var(--line); opacity: .55; animation: none; }
.approval.expired .ap-head, .clarify.expired .cl-head { color: var(--dimmer); }

/* #1: send button busy pulse — "working on it", never looks switched off */
.send-btn.busy { animation: sendpulse .8s ease-in-out infinite; }
@keyframes sendpulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }

/* #2: lightbox — fullscreen in-app photo viewer, fat ✕ top-right */
.lightbox {
  position: fixed; inset: 0; z-index: 95; background: rgba(0,0,0,.92);
  display: flex; align-items: center; justify-content: center;
}
.lightbox img {
  max-width: 94vw; max-height: 84dvh; object-fit: contain;
  border-radius: 8px; border: 1px solid var(--line);
}
#lightbox-x {
  position: fixed; top: calc(12px + env(safe-area-inset-top)); right: 14px;
  min-width: 48px; min-height: 48px; font-size: 20px; z-index: 96;
  background: var(--bg3); color: var(--fg); border: 1px solid var(--line); border-radius: 999px;
}
#lightbox-x:hover { color: var(--red); border-color: var(--red); }

/* #12: tool trail — numbered, indented step list inside the live bubble */
.lw-step { display: flex; gap: 9px; padding: 1px 0; }
.lw-n {
  color: var(--dimmer); font-size: 10px; letter-spacing: 1px;
  padding-top: 2px; flex-shrink: 0; font-variant-numeric: tabular-nums;
}
.lw-t { color: var(--dim); word-break: break-word; overflow-wrap: anywhere; min-width: 0; }
.lw-step:last-child .lw-t { color: var(--fg); }   /* active step reads brightest */
/* 2026-07-25: the 5-step partition line was var(--line) #1d2833 — basically
   invisible ("too dim and dark"). Lifted to a readable slate. */
.lw-sep { border-top: 1px dashed rgba(147,169,188,.5); margin-top: 5px; padding-top: 6px; }
.lw-fold { color: var(--dimmer); text-align: center; font-size: 10px; letter-spacing: 2px; padding: 2px 0; }

/* 2026-07-25 batch: retractable workings boxes, slips, ticker */
.lw-head { cursor: pointer; }
.lw-caret { margin-left: auto; color: var(--dimmer); font-size: 10px; }
.livework.collapsed .lw-step, .livework.collapsed .lw-fold,
.livework.sealed.collapsed .lw-step, .livework.sealed.collapsed .lw-fold { display: none; }
.livework.collapsed .lw-hb { display: none; }
.livework.sealed { border-color: var(--line); opacity: .85; }
.livework.sealed .lw-head { color: var(--dim); }
/* expanded sealed box: the ticker duplicates the last step — hide it */
.livework.sealed:not(.collapsed) .lw-ticker { display: none; }
.lw-ticker {
  font-family: var(--mono); font-size: 11px; color: var(--fg);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  animation: tickflash .6s ease-out;
}
.livework.sealed .lw-ticker { color: var(--dimmer); animation: none; }
@keyframes tickflash { from { color: var(--cyan); } to { color: var(--fg); } }
/* #11 (2026-08-04): springy interrupt ring — pops in with overshoot (outer
   span springs scale), inner ring spins until real progress clears it */
.lw-ring { display: inline-flex; flex-shrink: 0; animation: ringpop .5s cubic-bezier(.34,1.56,.64,1); }
.lw-ring i {
  width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid rgba(167,139,250,.22); border-top-color: var(--violet);
  animation: ringspin .7s linear infinite;
}
@keyframes ringpop { 0% { transform: scale(0); } 70% { transform: scale(1.4); } 100% { transform: scale(1); } }
@keyframes ringspin { to { transform: rotate(360deg); } }
.lw-slip {
  border-left: 3px solid var(--amber); background: rgba(245,185,66,.07);
  color: var(--amber); padding: 4px 8px; border-radius: 0 6px 6px 0; font-size: 11.5px;
}
.lw-qslip {
  border-left: 3px solid #a78bfa; background: rgba(167,139,250,.08);
  color: #a78bfa; padding: 4px 8px; border-radius: 0 6px 6px 0; font-size: 11.5px;
  border-top: 1px dashed rgba(167,139,250,.35); margin-top: 2px; padding-top: 6px;
}

/* #16: transcript loading spinner */
.tx-loading {
  align-self: center; color: var(--dim); display: flex; align-items: center; gap: 9px;
  padding: 22px 0; letter-spacing: 1px; font-size: 12px;
}
.tx-spin {
  width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid var(--line); border-top-color: var(--cyan);
  animation: txspin .8s linear infinite;
}
@keyframes txspin { to { transform: rotate(360deg); } }

/* ---------- FIX 3 (2026-07-29): drawer quick-picks (topbar chip removed
   2026-07-30 — model said twice inside a chat) ---------- */
.drawer-models {
  padding: 8px 10px 6px; border-bottom: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 6px;
}
.dm-cur {
  width: 100%; text-align: left; font-family: var(--mono); font-size: 11px;
  color: var(--cyan); background: rgba(56,225,212,.08);
  border: 1px solid rgba(56,225,212,.3); border-radius: 8px;
  padding: 7px 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dm-cur:hover:not(:disabled) { background: rgba(56,225,212,.18); }
.dm-cur:disabled { opacity: .4; }
/* model-locked instance (his #7, 2026-08-04): the drawer model row says
   LOCKED in violet — open the hamburger and you KNOW what it's welded to */
.dm-cur.locked { color: var(--violet); background: rgba(167,139,250,.10); border-color: rgba(167,139,250,.45); }
.dm-cur.locked:hover:not(:disabled) { background: rgba(167,139,250,.20); }

/* ---------- BIG EDITOR OVERLAY (#4, 2026-08-04): fullscreen writing surface */
.editor-overlay {
  position: fixed; inset: 0; z-index: 92; background: var(--bg);
  display: flex; flex-direction: column; height: var(--vvh, 100dvh);
  padding-top: env(safe-area-inset-top);
}
.ed-head {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--line); flex-shrink: 0;
}
.ed-title {
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--cyan); letter-spacing: 2px; font-size: 12px;
}
.ed-count { color: var(--dimmer); font-size: 11px; letter-spacing: 1px; flex-shrink: 0; }
#ed-clear { flex-shrink: 0; }
#ed-close { min-width: 44px; min-height: 44px; flex-shrink: 0; }
#ed-input {
  flex: 1; width: 100%; background: var(--bg); color: var(--fg);
  border: none; outline: none; resize: none;
  font-family: var(--mono); font-size: 15.5px; line-height: 1.55; padding: 16px;
  overscroll-behavior: contain; touch-action: pan-y;
}
.ed-foot {
  display: flex; align-items: center; gap: 12px; flex-shrink: 0;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
}
body.kb-open .ed-foot { padding-bottom: 6px; }
.ed-mode { flex: 1; color: var(--dim); font-size: 11.5px; letter-spacing: 1.5px; }
/* 2026-08-08 (his #1): .send-btn is a fixed 44×44 SQUARE — the editor's
   "➤ SEND" text overflowed it ("popping out of the little box"). The editor
   send is a real pill now, tinted by the armed mode like the composer. */
.ed-send {
  width: auto; min-width: 44px; height: auto; min-height: 44px;
  padding: 10px 22px; letter-spacing: 2px; font-size: 13px; flex-shrink: 0;
}
.ed-send.mode-steer { border-color: var(--amber); color: var(--amber); background: rgba(245,185,66,.1); }
.ed-send.mode-queue { border-color: var(--violet); color: var(--violet); background: rgba(167,139,250,.1); }
.ed-send.mode-pg { border-color: var(--green); color: var(--green); background: rgba(60,232,138,.1); }

/* ========================================================================
   2026-08-08 — MEGA BATCH (his 19-item list)
   ======================================================================== */

/* fixed-order label (his #9, 2026-08-11 — sort select + MY RANK are DEAD) */
.sort-row {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-bottom: 1px solid var(--line);
}
.sort-fixed-label {
  flex: 1; min-width: 0; font-family: var(--mono); font-size: 8.5px;
  letter-spacing: 1px; color: var(--dimmer); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.icon-btn.small { min-width: 32px; min-height: 32px; font-size: 13px; }

/* #18 — the glowing IDLE-duration pill (replaces the mystery timestamp);
   2026-08-11 his #9: the pill's emoji + color are the idle-HEAT grade,
   painted inline from idleHeat() (see app.js) */
.card-time.card-idle {
  color: var(--green); border: 1px solid rgba(60,232,138,.45); border-radius: 999px;
  padding: 1px 8px; font-size: 9.5px; letter-spacing: 1px; font-weight: 700;
  box-shadow: 0 0 9px rgba(60,232,138,.16); background: rgba(60,232,138,.06);
  font-variant-numeric: tabular-nums;
}

/* #13/#12 — the hero is the identity; a fresh card shows a ghost invitation */
.card-hero.ghost {
  color: var(--dimmer); border-style: dashed; border-color: var(--line);
  background: transparent; font-style: italic;
}
/* #5 — idle-on-a-question hero: dotted amber frame over the green */
.card-hero.dotted { border-style: dotted !important; }

/* #9 — fresh session: the sparkled NEW pill already screams; header version */
.status-box.fresh {
  color: var(--cyan); border-color: var(--cyan); background: rgba(56,225,212,.10);
  animation: pulse-cyan 1.4s ease-in-out infinite;
}

/* #10 — CARD MAIN LINE flip (GOAL ⇄ LATEST TEXT) */
.hero-flip { display: flex; gap: 8px; margin: 4px 0 2px; }
.hero-flip .mini-chip { flex: 1; min-height: 34px; font-size: 11px; }

/* #19 — long-message fold (HIS walls only, 2026-08-11 his #6): faded peek +
   fold bar. The bar carries its own ⧉ COPY ALL (his #8) — while folded the
   corner ⧉ hides and this one never does. */
.msg.has-fold .msg-text {
  max-height: 320px; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 62%, rgba(0,0,0,.25) 88%, transparent);
  mask-image: linear-gradient(#000 62%, rgba(0,0,0,.25) 88%, transparent);
}
.msg.has-fold.open .msg-text { max-height: none; -webkit-mask-image: none; mask-image: none; }
.fold-row { display: flex; gap: 6px; align-items: stretch; margin-top: 4px; }
.fold-toggle {
  flex: 1; display: block;
  background: rgba(56,225,212,.06); border: 1px dashed rgba(56,225,212,.4);
  color: var(--cyan); border-radius: 6px; padding: 6px 10px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 1px;
  min-height: 32px;
}
.fold-toggle:hover { background: rgba(56,225,212,.14); }
.fold-copy {
  position: static; opacity: 1; min-width: 44px; min-height: 32px; flex-shrink: 0;
  background: rgba(56,225,212,.06); border: 1px dashed rgba(56,225,212,.4);
  color: var(--cyan); border-radius: 6px; font-size: 14px;
}
.fold-copy:hover { background: rgba(56,225,212,.14); }
.msg.has-fold:not(.open) > .copy-btn { display: none; }   /* the bar's ⧉ serves */

/* ---------- TYPEWRITER (#13, 2026-08-04): live bot bubbles type in ---------- */
.msg-text.typing { white-space: pre-wrap; }
.tw-caret { color: var(--cyan); font-size: 12px; animation: twblink .7s steps(1) infinite; }
@keyframes twblink { 50% { opacity: 0; } }
.dm-favs { display: flex; flex-wrap: wrap; gap: 5px; }
.dm-fav {
  font-family: var(--mono); font-size: 10px; color: var(--dim);
  background: none; border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 9px; max-width: 46%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dm-fav:hover:not(:disabled):not(.on) { color: var(--fg); border-color: var(--dim); }
.dm-fav.on { color: #061014; background: var(--cyan); border-color: var(--cyan); font-weight: 700; }
.dm-fav:disabled { opacity: .4; }
.dm-hint { font-family: var(--mono); font-size: 9px; color: var(--dimmer); line-height: 1.5; }

/* ---------- ✂ WALLPAPER CROP (2026-08-15, his wallpaper edit mode) ---------- */
.crop-box { width: min(560px, 94vw); }
.crop-stage {
  position: relative; width: 100%; height: min(52vh, 420px);
  background: #05080b; border: 1px solid var(--line); border-radius: 8px;
  overflow: hidden; touch-action: none;   /* pinch/pan live here, no page scroll */
}
#crop-canvas { width: 100%; height: 100%; display: block; cursor: grab; }
#crop-canvas:active { cursor: grabbing; }
.crop-zoom { width: 100%; margin: 10px 0 2px; accent-color: var(--cyan); }
