/* ── ClawTerminal Studio ───────────────────────────────────────────────
   An app, not a page: fixed chrome, one scrolling canvas, dense hairline
   panels. Builds on the tokens in /ascii.css so Studio and the landing
   read as one product. Extra tokens below are app-only. */
:root{
  --rail:264px; --top:52px;
  /* --ok, --warn, --ease and the eight series slots now come from
     /ascii.css, which is the design system's token layer. They used to be
     redeclared here, and because this file loads AFTER ascii.css that
     redeclaration won — so correcting the palette upstream would have
     changed nothing in Studio, which is the only place the palette is
     actually used. The old set failed colour-vision validation: the olive
     #9aa66b read as grey (chroma 0.082) and collided with the pink #e07a9c
     under deuteranopia at ΔE 6.0. The replacements are validated as an
     ordered set — see the note in ascii.css. ct-render.js reads them by
     name from getComputedStyle, so the names are unchanged. */
}
/* A class rule with `display` beats the UA stylesheet's [hidden]{display:none},
   so `.scrim{display:flex}` left the palette scrim and the chart lightbox
   permanently on top of the page — the whole app rendered behind a dimmer
   with an empty modal over it. Restore the attribute's meaning globally. */
[hidden]{display:none !important}
html,body{height:100%}
body{overflow:hidden;background:var(--bg);background-image:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
input,textarea{font:inherit;color:inherit;background:none;border:0;outline:none}
kbd{border:1px solid var(--line-2);border-radius:3px;padding:1px 5px;color:var(--dim);font-size:10px}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-thumb{background:#1d1719;border-radius:6px}
::-webkit-scrollbar-thumb:hover{background:#2a2124}
::-webkit-scrollbar-track{background:transparent}

/* ── chrome ─────────────────────────────────────────────────────── */
.app{display:grid;grid-template-columns:var(--rail) 1fr;grid-template-rows:var(--top) 1fr;height:100vh;height:100dvh}
.app.norail{grid-template-columns:0 1fr}
.app.norail .rail{display:none}
.topbar{
  grid-column:1/-1;display:flex;align-items:center;gap:16px;padding:0 16px;
  border-bottom:1px solid var(--line);background:var(--panel);z-index:20;
}
.rail-toggle{color:var(--dim);font-size:14px;padding:5px 8px;border-radius:4px;display:none}
.rail-toggle:hover{color:var(--ink);background:var(--panel-2)}
.tb-brand{display:flex;align-items:center;gap:9px;font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;flex:none}
.tb-brand img{width:24px;height:24px;border-radius:4px;object-fit:cover;object-position:50% 28%;transform:scale(1.3);image-rendering:pixelated;border:1px solid rgba(238,87,65,.4)}
.tb-brand b{color:var(--accent)}
.tb-tabs{display:flex;gap:2px;flex:none}
.tb-tabs button{
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);
  padding:7px 13px;border-radius:4px;transition:color .15s,background .15s
}
.tb-tabs button:hover{color:var(--ink)}
.tb-tabs button.on{color:var(--accent);background:rgba(238,87,65,.09)}
.palette-hint{
  flex:1;max-width:420px;margin:0 auto;display:flex;align-items:center;gap:10px;
  border:1px solid var(--line);border-radius:6px;background:var(--bg);
  padding:7px 12px;font-size:12px;color:var(--faint);transition:border-color .15s,color .15s
}
.palette-hint:hover{border-color:var(--line-2);color:var(--dim)}
.palette-hint kbd{margin-left:auto}
.tb-right{display:flex;align-items:center;gap:16px;font-size:11px;color:var(--dim);letter-spacing:.1em;flex:none}
.tb-dot{width:6px;height:6px;border-radius:50%;background:var(--ok);display:inline-block;margin-right:7px;vertical-align:middle}
.tb-dot.off{background:var(--accent-dim)}
.tb-right a:hover{color:var(--ink)}

/* ── rail ───────────────────────────────────────────────────────── */
.rail{border-right:1px solid var(--line);background:var(--panel);overflow-y:auto;display:flex;flex-direction:column}
.rail-search{padding:12px 14px 8px;position:sticky;top:0;background:var(--panel);z-index:2}
.rail-search input{
  width:100%;border:1px solid var(--line);border-radius:5px;padding:7px 10px;font-size:12px;background:var(--bg)
}
.rail-search input:focus{border-color:var(--line-2)}
#railBody{padding-bottom:26px}
.rail-h{display:flex;align-items:center;gap:8px;padding:14px 16px 7px;font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:var(--faint)}
.rail-h .ct{color:var(--faint);opacity:.6}
.rail-h button{margin-left:auto;color:var(--dim);font-size:15px;line-height:1;padding:2px 6px;border-radius:3px}
.rail-h button:hover{color:var(--accent);background:rgba(238,87,65,.1)}
.rail-row{display:flex;align-items:center;border-left:2px solid transparent;transition:background .12s}
.rail-row:hover{background:var(--panel-2)}
.rail-row.on{border-left-color:var(--accent);background:var(--panel-2)}
.rail-row .go{
  flex:1;text-align:left;padding:8px 6px 8px 14px;font-size:12px;color:var(--soft);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis
}
.rail-row:hover .go,.rail-row.on .go{color:var(--ink)}
.rail-row .del{opacity:0;color:var(--faint);font-size:14px;padding:4px 10px;transition:opacity .12s,color .12s}
.rail-row:hover .del{opacity:1}
.rail-row .del:hover{color:var(--accent)}
.rail-empty{padding:4px 16px 12px;font-size:11px;color:var(--faint);line-height:1.7}
/* In-place rename. Sits exactly where the label was so the row does not
   jump when it turns into a field. */
.rail-row .go-edit{
  flex:1;min-width:0;margin:0 6px 0 12px;padding:5px 6px;font:inherit;font-size:12px;
  color:var(--ink);background:var(--bg);border:1px solid var(--accent);border-radius:4px;outline:none
}

/* ── canvas ─────────────────────────────────────────────────────── */
/* Flex column so a SHORT answer still leaves the composer docked at the
   bottom (#view takes the slack) while a long one lets it stick there. */
.canvas{position:relative;overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth;
  display:flex;flex-direction:column}
#view{flex:1 0 auto}
/* The composer is sticky and therefore occupies its own flow space, so
   the stream no longer has to reserve room for it by hand. */
.stream{max-width:920px;margin:0 auto;padding:32px 30px 36px}

/* empty state */
.hero{max-width:900px;margin:0 auto;padding:7vh 30px 40px;text-align:center;transition:opacity .3s ease,transform .35s var(--ease)}
.hero.out,#below.out{opacity:0;transform:translateY(-10px);pointer-events:none}
.app.landing #view{flex:none}
/* The empty stream still carries its 150px bottom padding (reserved for
   the docked composer), which on the landing state is 180px of dead air
   between the headline and the composer. */
.app.landing .stream{padding:0}
.app.landing .hero{padding:0 30px 18px}
.app.landing .hero .mark{margin-bottom:14px}
.app.landing .hero h1{margin-bottom:12px}
.app.landing .hero p{font-size:12.5px;max-width:54ch}
#below{transition:opacity .3s ease,transform .35s var(--ease);max-width:900px;margin:0 auto;width:100%;padding:0 30px}
#below .starts,#below .surface{opacity:0;transform:translateY(8px);animation:ct-riseup .55s var(--ease) .3s forwards}
#below .surface{margin-top:16px}
@keyframes ct-riseup{to{opacity:1;transform:none}}
.hero .mark{font-size:10px;letter-spacing:.32em;text-transform:uppercase;color:var(--faint);margin-bottom:20px}
.hero h1{font-size:clamp(23px,3.5vw,36px);font-weight:500;line-height:1.28;letter-spacing:.005em;margin-bottom:14px}
.hero h1 em{color:var(--accent)}
.hero p{color:var(--dim);font-size:13px;max-width:58ch;margin:0 auto;line-height:1.75}
.starts{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line);border:1px solid var(--line);border-radius:7px;overflow:hidden;text-align:left}
.start{background:var(--bg);padding:13px 15px;transition:background .15s}
.start:hover{background:var(--panel)}
.start .k{display:block;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
.start .t{font-size:12.5px;color:var(--soft);line-height:1.55}
.start:hover .t{color:var(--ink)}
.surface{display:flex;flex-wrap:wrap;gap:7px;justify-content:center;margin-top:26px}
.surface span{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--faint);border:1px solid var(--line);border-radius:20px;padding:4px 11px}

/* blocks */
.blk{margin-bottom:26px;animation:rise .3s var(--ease) both}
@keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.q{display:flex;gap:12px;align-items:flex-start;padding-bottom:4px}
.q .caret{color:var(--accent);font-weight:700;flex:none}
.q .txt{font-size:15px;color:var(--ink);line-height:1.55}

/* ── tool trace: the convergence motif, running live ──────────────────
   Every source runs a wire into a shared bus, and the bus feeds the
   answer — the same picture the landing page draws in ASCII, except
   here the wires are real calls and a packet only moves while one is
   actually open. The 15-30s before the first token is the most
   interesting thing this machine does; a spinner throws all of it away.
   The panel opens itself to show the work and folds back to one line
   the moment prose starts, unless the reader has touched it. */
.trace{border:1px solid var(--line);border-radius:6px;background:var(--panel);margin:10px 0 14px;overflow:hidden}
.trace-h{display:flex;align-items:center;gap:9px;padding:9px 13px;font-size:11px;color:var(--dim);letter-spacing:.08em;cursor:pointer;width:100%;text-align:left}
.trace-h:hover{color:var(--soft)}
.trace-h .n{color:var(--accent)}
/* Live, the header is the loud thing on screen. Finished, it is a
   receipt sitting above the answer — it should not out-shout it. */
.trace[data-state=done] .trace-h .n{color:var(--soft)}
.trace-h .chev{margin-left:auto;transition:transform .18s var(--ease)}
.trace.open .trace-h .chev{transform:rotate(90deg)}

/* State glyph. Same vocabulary as the design system's progress row, so
   a run reads the same here as it does anywhere else in the product. */
.trace-h .st{flex:none;font-size:10px;line-height:1;width:8px;color:var(--dim)}
.trace-h .st::before{content:"\00b7"}
.trace[data-state=planning] .st::before,
.trace[data-state=reading] .st::before,
.trace[data-state=writing] .st::before{content:"\25b8"}
.trace[data-state=done] .st::before{content:"\2713"}
.trace[data-state=failed] .st::before{content:"\00d7"}
.trace[data-state=planning] .st,
.trace[data-state=reading] .st,
.trace[data-state=writing] .st{color:var(--accent);animation:ct-blink 1.5s ease-in-out infinite}
.trace[data-state=done] .st{color:var(--green)}
.trace[data-state=failed] .st{color:var(--accent)}
@keyframes ct-blink{0%,100%{opacity:1}50%{opacity:.35}}

/* Collapse animates on grid-template-rows so it works without knowing
   the height, which changes on every appended call. */
.trace-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .34s var(--ease)}
.trace.open .trace-body{grid-template-rows:1fr}
.tflow{overflow:hidden;min-height:0;display:flex;align-items:center;border-top:1px solid var(--line)}

/* the bus: one vertical line every wire terminates on */
.tflow-wires{
  flex:1;min-width:0;padding:6px 0;position:relative;
  border-right:1px solid var(--line-2);
  max-height:min(44vh,360px);overflow-y:auto;scrollbar-width:thin;
  transition:border-color .3s var(--ease);
}
.trace[data-state=reading] .tflow-wires{border-right-color:var(--accent-dim)}

/* Before the first call there is nothing to draw, so the empty bus
   sweeps. Deliberately abstract — inventing placeholder rows here would
   read as data that does not exist yet. */
.trace.planning .tflow-wires{min-height:68px}
.trace.planning .tflow-wires::before{
  content:"selecting sources";position:absolute;left:13px;top:50%;transform:translateY(-50%);
  font-size:11px;color:var(--faint);letter-spacing:.04em;
}
.trace.planning .tflow-wires::after{
  content:"";position:absolute;left:13px;right:0;top:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--accent),transparent);
  opacity:.5;animation:ct-scan 2.2s var(--ease) infinite;
}
@keyframes ct-scan{0%{top:6px;opacity:0}18%{opacity:.5}82%{opacity:.5}100%{top:62px;opacity:0}}

/* Once the log outgrows its box the cut edge is masked, so a row is
   never sliced in half at the fold. Only when it actually scrolls —
   otherwise the first and last rows would fade for no reason. */
.tflow-wires.fade{
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 14px,#000 calc(100% - 14px),transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 14px,#000 calc(100% - 14px),transparent 100%);
}

.tcall{display:flex;gap:10px;align-items:center;padding:5px 0 5px 13px;font-size:11px;line-height:1.6}
.tcall .nm{color:var(--soft);flex:none}
.tcall .ms{color:var(--faint);flex:none;font-size:10px;width:112px;text-align:right;font-variant-numeric:tabular-nums}
.tcall.run .nm{color:var(--accent)}

/* Per-call state. `done` is set explicitly rather than inferred from
   "no longer running", so a call the stream abandoned keeps the neutral
   dot instead of inheriting a tick it never earned. */
.tcall .st{flex:none;width:8px;font-size:9px;line-height:1;color:var(--faint)}
.tcall .st::before{content:"\00b7"}
.tcall.run .st{color:var(--accent);animation:ct-blink 1.5s ease-in-out infinite}
.tcall.run .st::before{content:"\25b8"}
.tcall.done .st{color:var(--green);animation:none}
.tcall.done .st::before{content:"\2713"}

/* Arguments as chips + key/value pairs instead of raw JSON. The value is
   the part worth reading, so the key is the dimmer of the two. */
.tcall .ar{position:relative;flex:1;min-width:0;display:flex;align-items:center;gap:8px;overflow:hidden;white-space:nowrap}
.tcall .chip{
  flex:none;font-size:10px;letter-spacing:.06em;color:var(--soft);
  border:1px solid var(--line-2);border-radius:3px;padding:1px 6px;
  background:var(--panel-2);
}
.tcall.run .chip{color:var(--accent);border-color:var(--accent-dim)}
.tcall .kv{flex:none;display:inline-flex;gap:5px;align-items:baseline;min-width:0}
.tcall .kv i{font-style:normal;color:var(--faint);font-size:10px}
.tcall .kv b{font-weight:400;color:var(--dim);min-width:0;overflow:hidden;text-overflow:ellipsis}
/* The tail is what gets cut on a narrow panel, so fade it out rather
   than ending on a hard clip mid-word. */
.tcall .ar::after{
  content:"";position:absolute;right:0;top:0;bottom:0;width:24px;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--panel));
}

/* the wire, and the packet that travels it */
.tcall .wire{
  flex:none;width:64px;height:1px;background:var(--line-2);position:relative;
  transition:background .5s var(--ease);
}
.tcall .wire i{
  position:absolute;left:0;top:50%;width:4px;height:4px;border-radius:50%;
  background:var(--accent);transform:translate(0,-50%);opacity:0;
}
.tcall.run .wire i{animation:ct-packet 1.15s linear infinite}
@keyframes ct-packet{
  0%{transform:translate(0,-50%);opacity:0}
  14%{opacity:1}
  86%{opacity:1}
  100%{transform:translate(62px,-50%);opacity:0}
}
/* delivered: the packet parks on the bus */
.tcall.done .wire::after{
  content:"";position:absolute;right:0;top:50%;width:3px;height:3px;border-radius:50%;
  background:var(--dim);transform:translate(50%,-50%);
}
.tcall.land .wire{background:var(--accent);transition:none}

/* the sink */
.tflow-sink{flex:none;display:flex;align-items:center;padding:0 14px 0 0}
.tflow-sink .lead{position:relative;width:34px;height:1px;background:var(--line-2);flex:none}
.tflow-sink .lead::after{
  content:"\25b8";position:absolute;right:-7px;top:50%;transform:translateY(-50%);
  font-size:9px;line-height:1;color:var(--line-2);
}
.tflow-sink .lead i{
  position:absolute;left:0;top:50%;width:4px;height:4px;border-radius:50%;
  background:var(--accent);transform:translate(0,-50%);opacity:0;
}
.trace[data-state=reading] .lead::after,
.trace[data-state=writing] .lead::after{color:var(--accent)}
.trace[data-state=reading] .lead i,
.trace[data-state=writing] .lead i{animation:ct-packet-lead 1.15s linear infinite}
@keyframes ct-packet-lead{
  0%{transform:translate(0,-50%);opacity:0}
  20%{opacity:1}
  80%{opacity:1}
  100%{transform:translate(32px,-50%);opacity:0}
}
.sink-box{
  margin-left:12px;padding:11px 14px;min-width:140px;
  border:1px solid var(--line-2);border-radius:5px;background:var(--panel-2);
  display:flex;flex-direction:column;gap:4px;
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease);
}
.sink-t{font-size:9.5px;letter-spacing:.18em;color:var(--dim)}
.sink-s{font-size:12.5px;color:var(--soft)}
.sink-n{font-size:10px;color:var(--faint);font-variant-numeric:tabular-nums}
.trace[data-state=reading] .sink-box,
.trace[data-state=writing] .sink-box{border-color:var(--accent-dim);box-shadow:0 0 30px -14px var(--accent)}
.trace[data-state=reading] .sink-s,
.trace[data-state=writing] .sink-s{color:var(--accent)}
.trace[data-state=done] .sink-s{color:var(--green)}
.trace[data-state=failed] .sink-s{color:var(--accent)}

/* Narrow: the diagram is the first thing to go — the log still reads. */
@media (max-width:860px){
  .tflow-sink{display:none}
  .tcall .wire{display:none}
  .tflow-wires{border-right:0}
  .tcall{padding-right:13px}
}
@media (prefers-reduced-motion:reduce){
  .tcall .wire i,.tflow-sink .lead i,.trace.planning .tflow-wires::after,
  .trace-h .st,.tcall.run .st{animation:none}
  .tcall.run .wire i{opacity:1;transform:translate(30px,-50%)}
}

/* thinking skeleton */
.skel{display:flex;flex-direction:column;gap:9px;padding:4px 0 6px}
.skel i{display:block;height:9px;border-radius:3px;background:linear-gradient(90deg,var(--panel) 25%,var(--panel-2) 50%,var(--panel) 75%);background-size:280% 100%;animation:sh 1.3s linear infinite}
.skel i:nth-child(1){width:88%}.skel i:nth-child(2){width:96%}.skel i:nth-child(3){width:62%}
@keyframes sh{from{background-position:180% 0}to{background-position:-80% 0}}

/* prose */
.prose{font-size:14px;line-height:1.78;color:var(--soft)}
.prose h1,.prose h2,.prose h3{color:var(--ink);font-weight:500;letter-spacing:.01em;margin:22px 0 9px;line-height:1.35}
.prose h1{font-size:18px}.prose h2{font-size:16px}.prose h3{font-size:14px}
.prose p{margin:0 0 12px}
.prose strong{color:var(--ink);font-weight:700}
.prose em{color:var(--accent);font-style:normal}
.prose code{background:var(--panel-2);border:1px solid var(--line);border-radius:3px;padding:1px 5px;font-size:12.5px;color:var(--ink)}
.prose pre{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:13px 15px;overflow-x:auto;margin:0 0 14px}
.prose pre code{background:none;border:0;padding:0;font-size:12.5px;color:var(--soft)}
.prose ul,.prose ol{margin:0 0 13px;padding-left:20px}
.prose li{margin:4px 0}
.prose li::marker{color:var(--accent-dim)}
.prose a{color:var(--accent);border-bottom:1px solid rgba(238,87,65,.3)}
.prose blockquote{border-left:2px solid var(--accent-dim);padding-left:14px;color:var(--dim);margin:0 0 13px}
.prose hr{border:0;border-top:1px solid var(--line);margin:20px 0}
.prose .tblwrap{overflow-x:auto;margin:0 0 16px;border:1px solid var(--line);border-radius:6px}
.prose table{width:100%;border-collapse:collapse;font-size:12.5px}
.prose th{
  text-align:left;color:var(--dim);font-weight:500;font-size:10px;letter-spacing:.13em;text-transform:uppercase;
  padding:9px 12px;border-bottom:1px solid var(--line-2);white-space:nowrap;cursor:pointer;user-select:none;
  position:sticky;top:0;background:var(--panel)
}
.prose th:hover{color:var(--ink)}
.prose th::after{content:"";opacity:.45;margin-left:6px}
.prose th.asc::after{content:"↑";color:var(--accent);opacity:1}
.prose th.desc::after{content:"↓";color:var(--accent);opacity:1}
.prose td{padding:8px 12px;border-bottom:1px solid var(--line);color:var(--soft);white-space:nowrap}
.prose tbody tr:last-child td{border-bottom:0}
.prose tbody tr:hover td{background:var(--panel)}
.tik{color:var(--accent);cursor:pointer;border-bottom:1px dotted rgba(238,87,65,.45)}
.tik:hover{background:rgba(238,87,65,.1)}

/* answer actions + followups */
.acts{display:flex;gap:4px;flex-wrap:wrap;margin-top:6px}
.acts button{
  font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);
  border:1px solid var(--line);padding:6px 11px;border-radius:5px;transition:color .14s,border-color .14s
}
.acts button:hover{color:var(--accent);border-color:var(--accent)}
.fups{margin-top:14px;display:flex;flex-direction:column;gap:6px}
.fups .lbl{font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--faint);margin-bottom:2px}
.fup{
  text-align:left;border:1px solid var(--line);border-radius:6px;padding:10px 13px;font-size:12.5px;color:var(--soft);
  transition:border-color .15s,color .15s,background .15s;display:flex;gap:10px;align-items:baseline
}
.fup:hover{border-color:var(--accent);color:var(--ink);background:rgba(238,87,65,.05)}
.fup::before{content:"→";color:var(--accent);flex:none}

/* ── asides: a question about one passage ─────────────────────────────
   Reads as a margin note and not as a second answer: indented behind a
   rule, one step smaller, quieter ink. The whole point is that it does
   not become the conversation — so it must not look like it either. */
.selpop{
  position:fixed;z-index:60;display:flex;gap:2px;padding:3px;
  border:1px solid var(--line-2);border-radius:6px;background:var(--panel);
  box-shadow:0 10px 30px -12px #000;animation:rise .14s var(--ease) both;
}
.selpop button{
  font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim);
  padding:5px 10px;border-radius:4px;transition:color .13s,background .13s;
}
.selpop button:hover{color:var(--accent);background:var(--panel-2)}

.asides{margin:2px 0 16px;display:flex;flex-direction:column;gap:10px}
.aside{
  border-left:2px solid var(--accent-dim);background:var(--panel);
  border-radius:0 6px 6px 0;padding:11px 14px 10px;
  animation:rise .22s var(--ease) both;
}
.aside.busy{border-left-color:var(--accent)}

.ah{display:flex;gap:8px;align-items:flex-start;padding-bottom:8px}
.ah .mk{color:var(--accent-dim);font-size:15px;line-height:1;flex:none}
/* The passage, not the answer to it. Two lines is plenty to recognise
   what was highlighted; more turns the note into a second copy of it. */
.ah .qt{
  flex:1;min-width:0;font-size:11.5px;line-height:1.5;color:var(--dim);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.ah .ax{flex:none;color:var(--faint);font-size:13px;line-height:1;padding:0 2px;transition:color .13s}
.ah .ax:hover{color:var(--accent)}

.aturns{display:flex;flex-direction:column;gap:12px}
.aturn{display:flex;flex-direction:column;gap:5px}
.aq{font-size:12px;color:var(--ink);display:flex;gap:8px;align-items:baseline}
.aq::before{content:">";color:var(--accent);flex:none}
.aa{font-size:13px;line-height:1.68}
.aa p:last-child{margin-bottom:0}
/* A chart inside a note is a footnote's illustration — smaller margins,
   no shouting. */
.aside .card{margin:8px 0 2px}
.aside .skel.sm i{height:8px}
.aside .skel.sm i:nth-child(1){width:70%}.aside .skel.sm i:nth-child(2){width:44%}

.aform{display:flex;gap:8px;align-items:baseline;margin-top:10px;border-top:1px solid var(--line);padding-top:9px}
.aform .ac{color:var(--accent);flex:none;font-size:12px}
.aform input{flex:1;min-width:0;font-size:12.5px;color:var(--ink)}
.aform input::placeholder{color:var(--faint)}

/* chart card */
.card{border:1px solid var(--line);border-radius:7px;background:var(--panel);margin:16px 0 18px;overflow:hidden}
.card-h{display:flex;align-items:center;gap:12px;padding:11px 14px;border-bottom:1px solid var(--line)}
.card-h .ttl{font-size:12px;color:var(--ink);letter-spacing:.02em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card-h .meta{font-size:10px;color:var(--faint);letter-spacing:.1em;flex:none}
.card-acts{margin-left:auto;display:flex;gap:2px;flex:none}
.card-acts button{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);padding:5px 9px;border-radius:4px;transition:color .14s,background .14s}
.card-acts button:hover{color:var(--accent);background:rgba(238,87,65,.1)}
.card-body{padding:8px 6px 4px;position:relative}
.legend{display:flex;flex-wrap:wrap;gap:14px;padding:2px 14px 12px;font-size:10.5px;color:var(--dim)}
.legend i{display:inline-block;width:9px;height:2px;margin-right:6px;vertical-align:middle;border-radius:1px}

/* ── chart motion ──────────────────────────────────────────────────
   The signature moment: you ask, the terminal visibly works, and then the
   chart draws itself. Each mark type animates the way that mark actually
   comes into being — a line strokes along its own path, a bar grows from
   the zero baseline it is measured against, a heatmap wipes along its
   diagonal. Decorative motion would be noise; this is the data arriving. */
@keyframes ct-draw{to{stroke-dashoffset:0}}
@keyframes ct-grow{from{transform:scaleY(0)}to{transform:scaleY(1)}}
@keyframes ct-grow-x{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes ct-fade{from{opacity:0}}
@keyframes ct-pop{from{opacity:0;transform:scale(.2)}}
.ctchart .draw-grow{animation:ct-grow .5s var(--ease) both;animation-delay:calc(var(--i,0) * .035s)}
.ctchart .draw-grow-x{animation:ct-grow-x .5s var(--ease) both;animation-delay:calc(var(--i,0) * .035s)}
.ctchart .draw-fade{animation:ct-fade .5s ease both;animation-delay:calc(var(--i,0) * .03s)}
.ctchart .draw-pop{animation:ct-pop .32s var(--ease) both;animation-delay:calc(var(--i,0) * .012s);transform-box:fill-box;transform-origin:50% 50%}
/* Axes and labels settle first so the marks land on a drawn stage. */
.ctchart .grid,.ctchart .axis,.ctchart .tick{animation:ct-fade .45s ease both}

/* svg chart internals */
.ctchart{display:block;width:100%;height:auto;overflow:visible}
.ctchart .grid{stroke:rgba(233,228,221,.055);stroke-width:1}
.ctchart .axis{stroke:var(--line-2);stroke-width:1}
.ctchart .tick{fill:var(--faint);font-size:9.5px;font-family:var(--mono)}
.ctchart .ln{fill:none;stroke-width:1.6;stroke-linejoin:round;stroke-linecap:round}
.ctchart .dot{stroke:var(--panel);stroke-width:1}
.ctchart .cross{stroke:var(--dim);stroke-width:1;stroke-dasharray:3 3;pointer-events:none}
.ctchart .up{fill:var(--s2);stroke:var(--s2)}
.ctchart .dn{fill:var(--accent);stroke:var(--accent)}
.tip{
  position:absolute;pointer-events:none;z-index:5;background:#0e0a0c;border:1px solid var(--line-2);
  border-radius:5px;padding:8px 11px;font-size:11px;color:var(--soft);white-space:nowrap;
  box-shadow:0 8px 26px rgba(0,0,0,.6);opacity:0;transition:opacity .1s
}
.tip.on{opacity:1}
.tip .th{color:var(--ink);margin-bottom:5px;font-size:10px;letter-spacing:.1em}
.tip .tr{display:flex;gap:14px;justify-content:space-between}
.tip .tr b{color:var(--ink);font-weight:500}

/* composer */
/* The composer IS the product on an empty canvas, so it starts centred
   and large; asking docks it to the bottom in one move. The transition is
   the app opening up — the same gesture as the answer arriving. */
/* STICKY, not absolute.
   Absolute inside a scrolling container resolves `bottom:0` against the
   initial box and then scrolls away with the content — so scrolling up
   dragged the input over the middle of the answer. Reserving padding
   underneath (the first attempt) hid the symptom at the very bottom of
   the page and did nothing anywhere else. Sticky pins it to the
   scrollport, which is what it always looked like it was doing. */
.composer{
  position:sticky;bottom:0;padding:14px 30px 18px;
  background:linear-gradient(to top,var(--bg) 64%,rgba(6,4,5,0));
  transition:bottom .55s var(--ease),padding .55s var(--ease);
}
/* On the empty canvas the whole thing is ONE centred column in normal
   flow — headline, then the composer, then the suggestions. Floating the
   composer at 50% instead made it land on top of the suggestions, because
   nothing was reserving the space it needed. */
/* `safe center` centres while there is room and falls back to flex-start
   when the column is taller than the viewport — plain `center` overflows
   BOTH ways and silently clips the headline off the top. */
.app.landing .canvas{display:flex;flex-direction:column;justify-content:safe center;padding:3vh 0 4vh}
.app.landing .composer{position:static;background:none;padding-top:0;padding-bottom:10px}
.app.landing #below{flex:none}
.app.landing .composer-in{
  max-width:660px;padding:16px 18px;border-color:rgba(238,87,65,.28);
  box-shadow:0 24px 70px rgba(0,0,0,.45);
}
.app.landing .composer-in textarea{font-size:15px}
.app.landing .hintbar{max-width:660px;justify-content:center;opacity:.75}
.app.landing #quota{margin-left:0}
.composer-in{
  max-width:920px;margin:0 auto;display:flex;align-items:flex-end;gap:11px;
  border:1px solid var(--line-2);border-radius:9px;background:var(--panel);padding:11px 13px;
  transition:border-color .18s,box-shadow .18s
}
.composer-in:focus-within{border-color:rgba(238,87,65,.55);box-shadow:0 0 0 3px rgba(238,87,65,.07)}
.composer-in .caret{color:var(--accent);font-weight:700;padding-bottom:2px;flex:none}
.composer-in textarea{flex:1;resize:none;font-size:14px;line-height:1.6;max-height:180px;color:var(--ink)}
.composer-in textarea::placeholder{color:var(--faint)}
.send{
  flex:none;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--bg);
  background:var(--accent);padding:8px 15px;border-radius:5px;font-weight:500;transition:filter .15s,opacity .15s
}
.send:hover{filter:brightness(1.09)}
.send:disabled{opacity:.32;cursor:not-allowed}
.send.stop{background:transparent;color:var(--accent);border:1px solid var(--accent)}
.hintbar{max-width:920px;margin:8px auto 0;display:flex;gap:16px;font-size:10px;color:var(--faint);letter-spacing:.08em;align-items:center}
#quota{margin-left:auto}

/* dashboards */
.dash{max-width:1240px;margin:0 auto;padding:26px 30px 60px}
.dash-h{display:flex;align-items:center;gap:14px;margin-bottom:8px}
.dash-h h2{font-size:17px;font-weight:500;color:var(--ink)}
.dash-h .sp{margin-left:auto;display:flex;gap:6px}
.dash-h button{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim);border:1px solid var(--line-2);padding:7px 12px;border-radius:5px}
.dash-h button:hover{color:var(--accent);border-color:var(--accent)}
.dash-sub{font-size:11px;color:var(--faint);margin-bottom:20px}
.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;align-items:start}
.grid .card{margin:0}
/* A widget spanning both columns — the "wide" toggle. */
.wcard.wide{grid-column:1/-1}
.wcard{cursor:grab;transition:border-color .15s,opacity .15s,transform .15s var(--ease)}
.wcard:active{cursor:grabbing}
.wcard.dragging{opacity:.4}
.wcard.dropto{border-color:var(--accent);transform:translateY(-2px)}
.wcard .tblwrap{border:0;border-radius:0;margin:0;max-height:340px}
#dashTitle{outline:none;border-bottom:1px solid transparent;padding-bottom:2px}
#dashTitle:hover{border-bottom-color:var(--line-2)}
#dashTitle:focus{border-bottom-color:var(--accent)}
@media(max-width:980px){.grid{grid-template-columns:1fr}}
.wempty{border:1px dashed var(--line-2);border-radius:7px;padding:44px 20px;text-align:center;color:var(--faint);font-size:12px;line-height:1.95}
.wempty b{color:var(--soft)}

/* command palette */
.scrim{position:fixed;inset:0;z-index:70;background:rgba(4,3,3,.66);backdrop-filter:blur(3px);display:flex;justify-content:center;align-items:flex-start;padding:12vh 20px 20px;animation:fade .14s var(--ease)}
.scrim.dark{background:rgba(4,3,3,.86);align-items:center;padding:40px}
@keyframes fade{from{opacity:0}to{opacity:1}}
.palette{width:min(640px,100%);border:1px solid var(--line-2);border-radius:10px;background:var(--panel);overflow:hidden;box-shadow:0 30px 80px rgba(0,0,0,.6);animation:pop .16s var(--ease)}
@keyframes pop{from{opacity:0;transform:translateY(-8px) scale(.99)}to{opacity:1;transform:none}}
.pal-in{display:flex;align-items:center;gap:11px;padding:14px 16px;border-bottom:1px solid var(--line)}
.pal-in .caret{color:var(--accent);font-weight:700}
.pal-in input{flex:1;font-size:14px}
.pal-list{max-height:52vh;overflow-y:auto;padding:6px 0}
.pal-item{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:9px 16px;font-size:13px;color:var(--soft)}
.pal-item .kind{font-size:9px;letter-spacing:.18em;text-transform:uppercase;color:var(--faint);flex:none;width:74px}
.pal-item .lbl{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pal-item.sel{background:var(--panel-2);color:var(--ink)}
.pal-item.sel .kind{color:var(--accent)}
.pal-empty{padding:18px 16px;font-size:12px;color:var(--faint)}

/* lightbox */
.lb-frame{width:min(1240px,100%);max-height:88vh;border:1px solid var(--line-2);border-radius:9px;background:var(--panel);display:flex;flex-direction:column;overflow:hidden}
.lb-head{display:flex;align-items:center;padding:13px 16px;border-bottom:1px solid var(--line);font-size:12px;color:var(--ink)}
.lb-head button{margin-left:auto;font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim)}
.lb-head button:hover{color:var(--accent)}
.lb-body{padding:16px;overflow:auto}

/* gate + toast */
.gate{max-width:540px;margin:12vh auto;text-align:center;padding:0 30px}
.gate h2{font-size:20px;font-weight:500;color:var(--ink);margin-bottom:12px}
.gate p{color:var(--dim);font-size:13px;line-height:1.8;margin-bottom:26px}
.gate form{display:flex;gap:8px;justify-content:center}
.gate input{border:1px solid var(--line-2);border-radius:6px;padding:11px 14px;font-size:13px;flex:1;max-width:290px;background:var(--panel)}
.gate input:focus{border-color:var(--accent)}
.gate .msg{margin-top:16px;font-size:12px;color:var(--dim);min-height:18px}
/* alerts */
.bell{display:flex;align-items:center;gap:7px;font-size:11px;letter-spacing:.1em;color:var(--dim);padding:5px 9px;border-radius:5px;transition:color .15s,background .15s}
.bell:hover{color:var(--ink);background:var(--panel-2)}
.bell i{font-style:normal;background:var(--accent);color:var(--bg);border-radius:9px;padding:1px 6px;font-size:10px;font-weight:700}
/* ── the Alerts section ───────────────────────────────────────────────
   Written in the design system's own token names (--color-*, --space-*)
   rather than Studio's legacy aliases, because this surface was rebuilt
   against `design-system/templates/alerts/` and the two should stay
   diffable. The aliases in ascii.css resolve to the same values either
   way; using the system names means a token change upstream lands here.

   The panel this replaces showed only what a watch FIRED. What it matches
   was invisible — which is how a watch labelled "New 13D activist filings"
   with every filter silently dropped read as healthy for a month. And
   state was carried by opacity alone, which is how fifteen deliberately
   paused watches read as fifteen broken ones. */
.alerts-view{max-width:1120px;margin:0 auto;padding:var(--space-8) var(--space-6) 90px}
.av-h h2{font-size:20px;font-weight:var(--font-heading-weight);color:var(--color-text);margin:0}
.av-h p{font-size:13px;color:var(--color-neutral-400);line-height:1.7;margin:var(--space-2) 0 0;max-width:64ch}
.av-h em{color:var(--color-neutral-200);font-style:normal}

/* ── the health row ─────────────────────────────────────────────────────
   Four figures that answer, unprompted, the question a user arrives at this
   page holding: is this thing even running? "Never fired" cannot tell a
   quiet watch from a dead scanner. These can. */
.health{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--color-divider);
  border:1px solid var(--color-divider);border-radius:var(--radius-md);overflow:hidden;
  margin:var(--space-6) 0}
.hstat{background:var(--color-bg);padding:var(--space-4) var(--space-6);display:grid;gap:2px}
.hstat .lb{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--color-neutral-500)}
.hstat .v{font-size:26px;line-height:1.15;font-weight:var(--font-heading-weight);
  font-variant-numeric:tabular-nums;color:var(--color-text)}
.hstat .v.is-live{color:var(--color-accent-2)}
.hstat .v.is-warn{color:var(--color-accent)}
.hstat .nt{font-size:11px;color:var(--color-neutral-500)}

.av-sec{display:flex;align-items:center;gap:var(--space-3);margin:var(--space-8) 0 var(--space-3);
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--color-neutral-500)}
.av-sec i{flex:1;height:1px;background:var(--color-divider);display:block}
.av-sec b{font-weight:400;color:var(--color-neutral-400);font-variant-numeric:tabular-nums;letter-spacing:.1em}

/* ── compose ────────────────────────────────────────────────────────── */
.wnew{display:flex;gap:var(--space-3);align-items:center;border:1px solid var(--color-divider);
  border-radius:var(--radius-md);padding:var(--space-3) var(--space-4);background:var(--color-surface);
  transition:border-color var(--motion-fast)}
.wnew:focus-within{border-color:var(--color-accent)}
.wnew .ac{color:var(--color-accent);font-weight:700;flex:none}
.wnew input{flex:1;min-width:0;font-size:13px;color:var(--color-text)}
.wnew input::placeholder{color:var(--color-neutral-600)}
.wnew button{flex:none;font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--color-neutral-500);border:1px solid var(--color-divider);border-radius:var(--radius-sm);
  padding:var(--space-2) var(--space-3);transition:color var(--motion-fast),border-color var(--motion-fast)}
.wnew button:hover{color:var(--color-accent);border-color:var(--color-accent)}

/* The draft. Shown, read, and only then saved — reviewing it is the whole
   feature. */
.wdraft{margin-top:var(--space-3);border:1px solid var(--color-accent-700);border-radius:var(--radius-md);
  background:var(--color-surface);padding:var(--space-4) var(--space-6);animation:rise .2s var(--ease) both}
.wd-h{display:flex;align-items:center;gap:var(--space-3)}
.wd-t{font-size:14px;color:var(--color-text)}
.wd-note{font-size:12px;color:var(--color-neutral-300);line-height:1.65;margin-top:var(--space-2)}
.wd-json{background:var(--color-bg);border:1px solid var(--color-divider);border-radius:var(--radius-sm);
  padding:var(--space-3);font-size:11px;color:var(--color-neutral-400);overflow-x:auto;
  margin:var(--space-3) 0 0;line-height:1.7}
.wd-a{display:flex;gap:var(--space-2);margin-top:var(--space-3)}
.wd-a button{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--color-neutral-500);
  border:1px solid var(--color-divider);border-radius:var(--radius-sm);padding:var(--space-2) var(--space-4);
  transition:color var(--motion-fast),border-color var(--motion-fast)}
.wd-a button:hover{color:var(--color-text);border-color:var(--color-divider-strong)}
.wd-a .go{color:var(--color-accent);border-color:var(--color-accent-700)}
.wd-a .go:hover{background:var(--color-accent-900);border-color:var(--color-accent)}
.wd-a button:disabled{opacity:.45;cursor:default}

/* ── watch grid ─────────────────────────────────────────────────────────
   One shared hairline between cells rather than a border per card: the grid
   is the container, the cards are its cells. */
.wgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(390px,1fr));gap:1px;
  background:var(--color-divider);border:1px solid var(--color-divider);
  border-radius:var(--radius-md);overflow:hidden}
.wcard{background:var(--color-bg);padding:var(--space-4) var(--space-6);display:flex;flex-direction:column;
  gap:var(--space-3);transition:background var(--motion-fast)}
.wcard:hover{background:var(--color-surface)}

/* State is said TWICE — a mark and a word — never by colour alone and never
   by opacity. Fifteen paused watches dimmed to 50% is precisely what made a
   user conclude none of their alerts worked. */
.wstate{display:inline-flex;align-items:center;gap:var(--space-2);font-size:9.5px;letter-spacing:.14em;
  text-transform:uppercase;flex:none}
.wstate::before{font-size:9px;line-height:1}
.wstate.is-live{color:var(--color-accent-2)}
.wstate.is-live::before{content:"\25CF";animation:ct-pulse 2s ease-in-out infinite}
.wstate.is-paused{color:var(--color-neutral-500)}
.wstate.is-paused::before{content:"\25CB"}
.wstate.is-broken{color:var(--color-accent)}
.wstate.is-broken::before{content:"\00D7";font-size:12px}
@keyframes ct-pulse{50%{opacity:.35}}

.wc-h{display:flex;align-items:center;gap:var(--space-3)}
.wc-t{font-size:13px;color:var(--color-text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.wc-ty{flex:none;font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--color-neutral-200);background:var(--color-neutral-900);border-radius:var(--radius-sm);
  padding:1px var(--space-2)}
/* Same chip vocabulary as the tool trace: a watch's filters and a tool
   call's arguments are the same kind of thing and should read alike. */
.wc-p{display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:baseline;min-height:18px}
.wc-p .chip{font-size:10px;letter-spacing:.06em;color:var(--color-accent-200);
  background:var(--color-accent-900);border-radius:var(--radius-sm);padding:1px var(--space-2)}
.wc-p .kv{display:inline-flex;gap:var(--space-1);align-items:baseline;font-size:10px}
.wc-p .kv i{font-style:normal;color:var(--color-neutral-500)}
.wc-p .kv b{font-weight:400;color:var(--color-neutral-300);font-variant-numeric:tabular-nums}
/* Said out loud, because this is the shape of the bug. */
.wc-any{font-size:11px;color:var(--color-accent)}
/* A watch that cannot work carries the reason in its own card. */
.wc-err{font-size:11px;line-height:1.55;color:var(--color-accent-200);background:var(--color-accent-900);
  border-left:2px solid var(--color-accent);border-radius:var(--radius-sm);
  padding:var(--space-2) var(--space-3)}
.wc-err b{font-weight:400;color:var(--color-accent-100)}

.wc-f{display:flex;align-items:center;gap:var(--space-3);margin-top:auto;padding-top:var(--space-1)}
.wc-n{font-size:10px;color:var(--color-neutral-400);font-variant-numeric:tabular-nums;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.wc-n em{font-style:normal;color:var(--color-neutral-500)}
.wc-a{margin-left:auto;display:flex;gap:var(--space-1);flex:none}
.wc-a button{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--color-neutral-500);
  padding:var(--space-1) var(--space-2);border-radius:var(--radius-sm);
  transition:color var(--motion-fast),background var(--motion-fast)}
.wc-a button:hover{color:var(--color-accent);background:var(--color-accent-900)}
.wc-a button.on:hover{color:var(--color-accent-2);background:var(--color-accent-2-900)}
.wspark{flex:none;overflow:visible}
.wspark rect.on{fill:var(--color-accent)}
.wspark rect.off{fill:var(--color-neutral-800)}

/* ── fired feed ─────────────────────────────────────────────────────────
   A list, not a card grid: these are scanned down a column, and one shared
   rule per day beats fifty boxes. The left edge carries the scanner's own
   salience so a 54%-of-class stake does not look like a routine 5.1% one. */
.day{display:flex;align-items:center;gap:var(--space-3);margin:var(--space-6) 0 var(--space-2);
  font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--color-neutral-500)}
.day i{flex:1;height:1px;background:var(--color-divider);display:block}
.day b{font-weight:400;color:var(--color-neutral-400);font-variant-numeric:tabular-nums}
.afeed{border:1px solid var(--color-divider);border-radius:var(--radius-md);overflow:hidden}
.arow{display:grid;grid-template-columns:74px 1fr auto auto;gap:var(--space-4);align-items:baseline;
  padding:var(--space-3) var(--space-6) var(--space-3) var(--space-4);
  border-bottom:1px solid var(--color-divider);
  border-left:2px solid color-mix(in srgb,var(--color-accent) calc(var(--sal,.3)*100%),var(--color-neutral-800));
  background:var(--color-surface);transition:background var(--motion-fast)}
.arow:last-child{border-bottom:0}
.arow:hover{background:var(--color-bg)}
.arow .tk{font-size:12px;color:var(--color-accent);overflow:hidden;text-overflow:ellipsis}
.arow .why{font-size:12px;line-height:1.5;color:var(--color-neutral-300)}
.arow .why b{font-weight:400;color:var(--color-text)}
.arow .lb{font-size:10px;letter-spacing:.08em;color:var(--color-neutral-400);white-space:nowrap}
.arow .ask{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--color-neutral-500);
  padding:var(--space-1) var(--space-2);border-radius:var(--radius-sm);white-space:nowrap;
  transition:color var(--motion-fast)}
.arow .ask::before{content:"\2192\00A0";color:var(--color-accent)}
.arow:hover .ask{color:var(--color-accent)}

/* ── watch detail sheet ─────────────────────────────────────────────────
   Ported from `design-system/templates/alerts-detail/`. Docked right rather
   than a centred modal: the grid it came from stays in place behind it, so
   opening a watch reads as going deeper into the page, not leaving it. */
.wsheet{position:fixed;inset:0;z-index:70;display:flex;justify-content:flex-end;
  background:color-mix(in srgb,var(--color-bg) 72%,transparent);animation:fade .16s var(--ease) both}
.wsheet .sheet{width:min(680px,100%);background:var(--color-bg);
  border-left:1px solid var(--color-divider);box-shadow:var(--shadow-lg);
  display:flex;flex-direction:column;overflow:hidden;animation:slidein .22s var(--ease) both}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes slidein{from{transform:translateX(24px);opacity:.4}to{transform:none;opacity:1}}
.sh-h{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-4) var(--space-6);
  border-bottom:1px solid var(--color-divider);background:var(--color-surface);flex:none}
.sh-t{font-size:14px;color:var(--color-text);flex:1;min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.sh-x{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--color-neutral-500);
  padding:var(--space-1) var(--space-2);border-radius:var(--radius-sm);
  transition:color var(--motion-fast),background var(--motion-fast)}
.sh-x:hover{color:var(--color-accent);background:var(--color-accent-900)}
.sh-b{flex:1;overflow-y:auto;padding:var(--space-6)}
.sh-sec{display:flex;align-items:center;gap:var(--space-3);margin:var(--space-6) 0 var(--space-3);
  font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--color-neutral-500)}
.sh-sec:first-child{margin-top:0}
.sh-sec i{flex:1;height:1px;background:var(--color-divider);display:block}
.sh-sec u{text-decoration:none;font-size:10px;letter-spacing:.1em;color:var(--color-neutral-400);
  font-variant-numeric:tabular-nums}

/* the number that decides whether the watch is worth keeping */
.perf{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--color-divider);
  border:1px solid var(--color-divider);border-radius:var(--radius-md);overflow:hidden}
.pcell{background:var(--color-bg);padding:var(--space-4) var(--space-6);display:grid;gap:2px}
.pcell .lb{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--color-neutral-500)}
.pcell .v{font-size:22px;line-height:1.2;font-weight:var(--font-heading-weight);
  font-variant-numeric:tabular-nums;color:var(--color-text)}
.pcell .v.pos{color:var(--color-pos)}
.pcell .v.neg{color:var(--color-neg)}
.pcell .nt{font-size:11px;color:var(--color-neutral-500);font-variant-numeric:tabular-nums}
/* Below the sample floor a median is noise, so it is not dressed as a
   result: no direction ink, and the cell says what it is short of. */
.pcell.thin .v{color:var(--color-neutral-400)}
.pnote{font-size:11px;line-height:1.65;color:var(--color-neutral-400);margin:var(--space-3) 0 0}
.pnote b{font-weight:400;color:var(--color-neutral-200)}

.ev{border:1px solid var(--color-divider);border-radius:var(--radius-md);overflow:hidden}
.ev-h,.erow{display:grid;grid-template-columns:58px 1fr 54px 72px;gap:var(--space-3)}
.ev-h{padding:var(--space-2) var(--space-4);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--color-neutral-500);border-bottom:1px solid var(--color-divider-strong)}
.ev-h .r{text-align:right}
.erow{align-items:baseline;padding:var(--space-3) var(--space-4);
  border-bottom:1px solid var(--color-divider);
  border-left:2px solid color-mix(in srgb,var(--color-accent) calc(var(--sal,.3)*100%),var(--color-neutral-800));
  background:var(--color-surface);transition:background var(--motion-fast)}
.erow:last-child{border-bottom:0}
.erow:hover{background:var(--color-bg)}
.erow .tk{font-size:12px;color:var(--color-accent);overflow:hidden;text-overflow:ellipsis}
.erow .why{font-size:11px;line-height:1.5;color:var(--color-neutral-300)}
.erow .why b{font-weight:400;color:var(--color-text)}
.erow .dt{font-size:10px;color:var(--color-neutral-500);font-variant-numeric:tabular-nums;text-align:right}
.erow .al{font-size:11px;font-variant-numeric:tabular-nums;text-align:right}
.erow .al.pos{color:var(--color-pos)}
.erow .al.neg{color:var(--color-neg)}
.erow .al.none{color:var(--color-neutral-500)}

/* A card is a door now, so it has to look like one. */
.wcard{cursor:pointer}
.wcard:focus-visible{outline:2px solid var(--color-accent);outline-offset:-2px}
.wc-a button{cursor:pointer}

/* ── an alert row, opened ───────────────────────────────────────────────
   The row already carries the whole payload — the accession, the holder,
   the stake. Expanding in place beats a second panel: you keep your place
   in the column you were reading. */
.arow{cursor:pointer}
.arow:focus-visible{outline:2px solid var(--color-accent);outline-offset:-2px}
.amore{grid-column:1/-1;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  gap:var(--space-2) var(--space-6);padding:var(--space-3) 0 var(--space-1);
  border-top:1px solid var(--color-divider);margin-top:var(--space-2);
  animation:rise .18s var(--ease) both}
.amore dl{display:flex;gap:var(--space-2);align-items:baseline;margin:0;font-size:11px}
.amore dt{color:var(--color-neutral-500);flex:none}
.amore dd{margin:0;color:var(--color-neutral-200);font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis}
.amore a{color:var(--color-accent);border-bottom:1px dotted var(--color-accent-700)}
.amore a:hover{border-bottom-style:solid}
@media(max-width:720px){
  .ev-h,.erow{grid-template-columns:52px 1fr 56px}
  .ev-h .h5,.erow .al{display:none}
}

.wempty{font-size:12px;color:var(--color-neutral-500);padding:var(--space-6);text-align:center;
  border:1px solid var(--color-divider);border-radius:var(--radius-md)}

@media(max-width:900px){
  .health{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:720px){
  .alerts-view{padding:var(--space-4) var(--space-4) 90px}
  .wgrid{grid-template-columns:1fr}
  .arow{grid-template-columns:1fr auto;gap:var(--space-2) var(--space-3)}
  .arow .why{grid-column:1/-1}
  .arow .lb{display:none}
}
.toast{
  position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(14px);z-index:80;
  background:#0e0a0c;border:1px solid var(--line-2);border-radius:6px;padding:10px 17px;font-size:12px;
  color:var(--soft);opacity:0;transition:opacity .2s,transform .2s var(--ease);pointer-events:none
}
.toast.on{opacity:1;transform:translateX(-50%)}
/* A toast that has somewhere to go has to be able to accept the click.
   The base toast is pointer-events:none so a passive notification never
   eats a click meant for the page underneath — but that also swallowed
   every click on the clickable variant, so a `go` toast announced a
   finished run, said "click to open", and then ignored being clicked.
   The JS had set .go and an onclick all along; CSS was discarding it. */
.toast.go{
  pointer-events:auto;cursor:pointer;
  border-color:var(--accent-dim);color:var(--ink)
}
.toast.go::after{content:" ↗";color:var(--accent)}
.toast.go:hover{border-color:var(--accent);background:#150e10}
.warn{border:1px solid rgba(232,176,75,.4);background:rgba(232,176,75,.06);border-radius:6px;padding:10px 13px;font-size:11.5px;color:var(--soft);margin:8px 0}
.err{border:1px solid var(--accent-dim);background:rgba(238,87,65,.07);border-radius:6px;padding:11px 14px;font-size:12px;color:var(--soft);margin:10px 0;display:flex;align-items:center;gap:12px}
.err button{margin-left:auto;font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--accent);flex:none}

@media(max-width:980px){
  .palette-hint{display:none}
}
@media(max-width:860px){
  /* ONE column, not `0 1fr`. Taking the rail out of flow (position:fixed)
     removes it as a grid item, so auto-placement shifts everything left and
     the canvas lands in the zero-width first column — the whole app renders
     as a 60px-wide sliver of unreadable text. */
  .app{grid-template-columns:1fr}
  .rail{position:fixed;top:var(--top);bottom:0;left:0;width:280px;z-index:30;transform:translateX(-101%);transition:transform .2s var(--ease)}
  .app.railopen .rail{transform:none;box-shadow:0 0 60px rgba(0,0,0,.6)}
  .rail-toggle{display:block}
  .stream,.composer{padding-left:16px;padding-right:16px}
  .starts{grid-template-columns:1fr}
  .hero{padding-top:4vh}
}

/* ── phone ──────────────────────────────────────────────────────────
   Every topbar child is flex:none, so below ~600px the bar could not
   shrink: it stayed at its intrinsic ~860px, and because it is a grid
   item spanning the app it dragged the whole document out to that width.
   The page then scrolled sideways and everything — heading, composer,
   example cards — was cut off at the right edge. Spanish hits this first
   (PREGUNTAR/PANELES/ALERTAS are wider than ASK/DASHBOARDS/ALERTS) but
   English overflows too, just a little later.

   What survives on a phone: the drawer toggle, the mascot, the three
   view tabs, the unread count, settings. What goes: the wordmark (the
   mascot still links home), the connection label (the dot keeps the
   signal), the bell's word, and the exit link. */
@media(max-width:600px){
  .topbar{gap:8px;padding:0 10px}
  .tb-brand span{display:none}
  .tb-tabs{flex:1 1 auto;min-width:0;overflow-x:auto;scrollbar-width:none}
  .tb-tabs::-webkit-scrollbar{display:none}
  .tb-tabs button{padding:7px 9px;letter-spacing:.07em;white-space:nowrap}
  .tb-right{gap:9px;min-width:0}
  .bell{padding:4px 6px}
  .bell span{display:none}
  .bell:has(i[hidden]){display:none}   /* nothing unread → no empty chip */
  /* Clip to the dot: the label is the user's email once signed in. */
  #status{width:6px;overflow:hidden;white-space:nowrap;flex:none}
  .tb-right > a{display:none}
}

/* The sign-in / gate form put input and button on one row with no wrap,
   so at phone widths the button was pushed off the edge. */
@media(max-width:560px){
  .gate{padding:0 18px;margin:8vh auto}
  .gate form{flex-wrap:wrap}
  .gate input{max-width:none;flex:1 1 100%}
  .gate form .send{flex:1 1 100%}
}
@media(prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* ── the job tray ────────────────────────────────────────────────────
   Runs continue on the server whether or not anyone is watching. The
   tray is what makes that legible: without it a backgrounded job and a
   lost one look identical. Bottom-LEFT so it never sits under the
   composer or the toast. */
.tray{
  position:fixed;left:16px;bottom:16px;z-index:60;width:min(330px,calc(100vw - 32px));
  background:var(--panel);border:1px solid var(--line-2);border-radius:8px;
  box-shadow:0 18px 46px rgba(0,0,0,.5);overflow:hidden;
  animation:slidein .18s var(--ease);
}
.tray-h{display:flex;align-items:center;justify-content:space-between;
  padding:9px 12px;border-bottom:1px solid var(--line);}
.tray-h .ttl{font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.tray-h .cap{font-size:11px;color:var(--faint);font-variant-numeric:tabular-nums}
.tray-j{display:flex;align-items:center;gap:9px;padding:9px 12px;font-size:12px;
  border-top:1px solid var(--line);color:var(--dim);cursor:default}
.tray-j:first-of-type{border-top:none}
.tray-j.open{cursor:pointer}
.tray-j:hover{background:rgba(255,255,255,.02)}
.tray-j .br{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tray-j .st{font-size:11px;color:var(--faint);flex:none}
.tray-j .dot{width:6px;height:6px;border-radius:50%;background:var(--faint);flex:none}
.tray-j.run .dot{background:var(--accent);animation:pulse 1.1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* ── compose a dashboard by describing it ───────────────────────────── */
.compose-bar{display:flex;align-items:center;gap:10px;margin:0 0 18px;
  padding:11px 14px;border:1px solid var(--line-2);border-radius:8px;
  background:var(--panel);transition:border-color .15s var(--ease)}
.compose-bar:focus-within{border-color:rgba(238,87,65,.5)}
.compose-bar .caret{color:var(--accent);font-weight:700;flex:none}
.compose-bar input{flex:1;font-size:13px;color:var(--ink);background:none;border:none;outline:none}
.compose-bar input::placeholder{color:var(--faint)}
.compose-bar button{flex:none;font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  padding:6px 12px;border:1px solid var(--line-2);border-radius:5px;color:var(--dim);
  background:none;cursor:pointer}
.compose-bar button:hover{border-color:var(--accent);color:var(--accent)}

.building{padding:22px 18px;border:1px dashed var(--line-2);border-radius:8px}
.building .lbl{font-size:12px;color:var(--dim);margin-bottom:14px}

/* The thinking indicator. A static panel during the 15-20s before the
   first tool call reads as a hang — the dots are the difference between
   "working" and "broken". */
.bthink{display:flex;align-items:center;gap:6px;margin-bottom:12px}
.bthink i{width:5px;height:5px;border-radius:50%;background:var(--accent);
  animation:bpulse 1.05s infinite}
.bthink i:nth-child(2){animation-delay:.16s}
.bthink i:nth-child(3){animation-delay:.32s}
.bthink .bstat{margin-left:6px;font-size:12px;color:var(--dim)}
@keyframes bpulse{0%,60%,100%{opacity:.22;transform:scale(.82)}30%{opacity:1;transform:scale(1)}}

/* Calls COUNTED, not listed. A board that reads fourteen ratings printed
   `get_rating` fourteen times down the page. */
.btools{display:flex;flex-wrap:wrap;gap:5px}
.bchip{display:inline-flex;align-items:baseline;gap:4px;padding:2px 7px;
  border:1px solid var(--line);border-radius:4px;font-size:11px;color:var(--faint);
  animation:fade .2s var(--ease)}
.bchip .k{color:var(--accent);font-variant-numeric:tabular-nums}

.bwidgets{margin-top:12px;display:flex;flex-direction:column;gap:4px}
.bw{display:flex;align-items:baseline;gap:8px;font-size:12px;color:var(--dim);
  animation:fade .22s var(--ease)}
.bw .ok{color:var(--accent);font-weight:700}
.tray-h .x{background:none;border:none;color:var(--faint);font-size:15px;line-height:1;
  cursor:pointer;padding:0 0 0 10px}
.tray-h .x:hover{color:var(--ink)}

/* A toast that can be opened says so, and reads as a control rather than
   a status line. */
#toast.go{cursor:pointer;border-color:rgba(238,87,65,.45)}
#toast.go:hover{border-color:var(--accent);color:var(--ink)}

/* Treemap / waterfall / bubble labels. Small and quiet: the shape is the
   message, the text is only there to say which shape you are looking at. */
.tm-l{fill:var(--ink);font-size:11px;font-weight:600}
.tm-p{fill:var(--dim);font-size:10px}
.wf-v{fill:var(--dim);font-size:10px;font-variant-numeric:tabular-nums}
.wf-link{stroke:var(--line-2);stroke-width:1;stroke-dasharray:2 3}
.bub-l{fill:var(--dim);font-size:10px}
.bw.fail{color:var(--faint)}
.bw.fail .ok{color:var(--faint)}
.tray-j .retry{background:none;border:1px solid var(--line-2);border-radius:4px;
  color:var(--faint);font-size:10px;letter-spacing:.06em;text-transform:uppercase;
  padding:2px 7px;cursor:pointer;flex:none}
.tray-j .retry:hover{border-color:var(--accent);color:var(--accent)}
.tray-j .retry:disabled{opacity:.4;cursor:default}
