/* ════════════════════════════════════════════════════════════════
   lab-demo.css — components for the /lab demos.

   Loaded AFTER css/site.css, and only by lab.html's four demo pages.
   No colour is defined here: every value comes from the site tokens, so a
   demo cannot drift from the rest of the site. Square corners, hairlines and
   mono indices — an instrument printed on the same paper as the pages that
   describe it.

   JS contracts kept intact (see js/consensus-lab.mjs, js/graph.mjs,
   lab/webllm/chat.mjs, lab/wasm-vs-js/bench.mjs):
     .nd / .nd-leader / .nd-dead      node strip
     .hb                              histogram bar (height set by JS)
     .ev / .ev-t / .ev-k / .ev-b      event feed rows
     .ged-l .gfl-l .gfu-c .gmk-p .glogbase .glog   SVG instrument
     .ok / .warn / .gate.ok / .gate.bad / .gate.warn-gate
     .message / .message-content / .error-banner   chat
   Element ids are the JS API; this file never renames one.
   ════════════════════════════════════════════════════════════════ */

/* ── Small caps label (stand-alone; site .label is a section eyebrow) ── */
.cap{
  font-family:var(--mono);font-size:var(--fs-mono-sm);letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);
}
.dim{color:var(--muted)}
.ok{color:var(--deep)}
.warn{color:var(--accent-ink)}
.num-t{font-variant-numeric:tabular-nums}

/* ── Plate: the instrument block ────────────────────────────── */
.plate{border:1px solid var(--line);background:var(--surface);padding:0;margin:0 0 var(--s-5)}
.plate--flush{background:transparent}
.plate__head{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:10px 18px;padding:14px 18px;border-bottom:1px solid var(--line);
}
.plate__head .cap{color:var(--ink)}
.plate__body{padding:18px}
.plate__foot{
  padding:12px 18px;border-top:1px solid var(--line);
  font-family:var(--mono);font-size:var(--fs-mono-sm);line-height:1.55;
  letter-spacing:.02em;color:var(--muted);
}
.plate__foot b{color:var(--ink);font-weight:500}
.plate > .note{margin:0;border:0;border-top:1px solid var(--line);border-left:0;background:transparent}

/* mono readouts inside a plate: numbers, not a sentence in caps */
.plate .mono,.stat .mono,.kv dd,.r-part .mono,.hist-foot{
  font-size:13px;letter-spacing:.02em;text-transform:none;
  color:var(--ink);font-variant-numeric:tabular-nums;
}

/* ── Controls ───────────────────────────────────────────────── */
.controls{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center}
.run-btn,.ghost-btn{
  display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  min-height:46px;padding:12px 22px;border:1px solid var(--ink);
  transition:background-color .2s var(--ease),color .2s var(--ease),border-color .2s var(--ease);
}
.run-btn{background:var(--ink);color:var(--on-dark)}
.run-btn:hover:not(:disabled){background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.ghost-btn{background:transparent;color:var(--ink);border-color:var(--line-strong)}
.ghost-btn:hover:not(:disabled){background:var(--ink);color:var(--on-dark);border-color:var(--ink)}
.run-btn:disabled,.ghost-btn:disabled{opacity:.42;cursor:not-allowed}
.run-btn:disabled:hover,.ghost-btn:disabled:hover{background:var(--ink);border-color:var(--ink);color:var(--on-dark)}
.ghost-btn:disabled:hover{background:transparent;color:var(--ink);border-color:var(--line-strong)}
.ghost-btn[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}

/* ── Fact band inside a narrow column (benchmark page) ──────── */
.facts--stack{grid-template-columns:repeat(2,minmax(0,1fr))}
.facts--stack .fact{padding:16px 14px;border-left:1px solid var(--line)}
.facts--stack .fact:nth-child(odd){border-left:0;padding-left:0}
.facts--stack .fact:nth-child(n+3){border-top:1px solid var(--line)}

/* ── Chat (WebLLM) ──────────────────────────────────────────── */
.statusline{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:var(--fs-mono-sm);letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted);
}
.status-dot{width:7px;height:7px;flex:none;background:var(--line-strong);border-radius:50%}
.status-dot.loading{background:var(--accent);animation:demo-blink 1.1s var(--ease) infinite}
.status-dot.ready{background:var(--deep)}
.status-dot.error{background:var(--danger);border-radius:0}
@keyframes demo-blink{0%,100%{opacity:1}50%{opacity:.25}}

.chat{display:grid;grid-template-columns:minmax(0,1fr) 306px;min-width:0}
.chat__main{display:flex;flex-direction:column;min-width:0;border-right:1px solid var(--line)}
.chat__error:empty{display:none}
.error-banner{
  border-bottom:1px solid var(--danger);border-left:2px solid var(--danger);
  background:var(--paper);color:var(--danger);
  font-family:var(--mono);font-size:var(--fs-mono-sm);line-height:1.55;
  letter-spacing:.02em;padding:12px 16px;
}
.chat__log{
  height:clamp(300px,46vh,430px);overflow-y:auto;padding:18px;
  display:flex;flex-direction:column;gap:10px;background:var(--paper);
}
.message{
  max-width:min(62ch,94%);
  font-size:var(--fs-small);line-height:1.55;
  padding:10px 13px;border:1px solid var(--line);background:var(--surface);
  overflow-wrap:break-word;
}
.message.assistant{align-self:flex-start;border-left:2px solid var(--line-strong)}
.message.user{align-self:flex-end;background:var(--ink);color:var(--on-dark);border-color:var(--ink)}
.message .message-content{white-space:pre-wrap}
.chat__form{
  display:flex;gap:10px;padding:14px 16px;border-top:1px solid var(--line);
  background:var(--surface);
}
.chat__form .input{flex:1 1 220px;min-width:0;width:auto}
.chat__form .run-btn{flex:0 0 auto}

.chat__rail{border-left:0;background:var(--paper);min-width:0}
.rail-block{padding:16px 18px;border-bottom:1px solid var(--line)}
.rail-block:last-child{border-bottom:0}
.rail-block > .cap{display:block;margin-bottom:10px;color:var(--ink)}
.rail-block .select{width:100%}
.rail-status{display:grid;grid-template-columns:auto minmax(0,1fr);gap:7px 12px;margin:0}
.rail-status dt{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.rail-status dd{margin:0;font-family:var(--mono);font-size:12px;letter-spacing:.02em;color:var(--ink);text-align:right;font-variant-numeric:tabular-nums}

.progress{display:none;margin-top:12px}
.progress-bar{height:6px;background:var(--surface);border:1px solid var(--line-strong)}
.progress-fill{height:100%;width:0;background:var(--accent);transition:width .2s linear}
.download-label{
  margin-top:7px;font-family:var(--mono);font-size:var(--fs-mono-sm);
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
  font-variant-numeric:tabular-nums;
}

.prompt-list{display:flex;flex-direction:column;gap:6px}
.prompt-btn{
  text-align:left;padding:9px 0;min-height:38px;
  font-family:var(--mono);font-size:12px;letter-spacing:.04em;color:var(--ink);
  border-bottom:1px solid var(--line);
  transition:color .18s var(--ease),border-color .18s var(--ease);
}
.prompt-btn::before{content:'+ ';color:var(--accent-ink)}
.prompt-btn:hover{color:var(--accent-ink);border-bottom-color:var(--accent-ink)}

.details{border-top:1px solid var(--line)}
.details summary{
  cursor:pointer;list-style:none;position:relative;padding:14px 26px 14px 0;
  font-family:var(--mono);font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);
}
.details summary::-webkit-details-marker{display:none}
.details summary::after{
  content:'+';position:absolute;right:0;top:50%;transform:translateY(-50%);
  font-size:16px;color:var(--accent-ink);
}
.details[open] summary::after{content:'–'}
.details .details__body{padding:0 0 16px}
.details .details__body p{font-size:var(--fs-small);line-height:1.6;color:var(--muted);margin:0 0 10px}
.details .details__body p:last-child{margin-bottom:0}
.details .details__body strong{color:var(--ink);font-weight:600}

/* ── Benchmark (WASM vs JS) ─────────────────────────────────── */
.bench-controls{display:flex;flex-wrap:wrap;gap:12px 22px;align-items:center}
.bench-field{display:flex;align-items:center;gap:9px;min-width:0}
.bench-field > label{
  font-family:var(--mono);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;
}
.bench-field .select{width:auto;min-width:132px}
.bench-env{
  margin:14px 0 0;font-family:var(--mono);font-size:var(--fs-mono-sm);
  line-height:1.6;letter-spacing:.01em;color:var(--muted);
}

#results[hidden]{display:none}
.results-grid{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  border-top:1px solid var(--ink);border-bottom:1px solid var(--ink);
  margin-top:var(--s-5);
}
.result-card{padding:18px 20px;min-width:0;border-left:1px solid var(--line)}
.result-card:first-child{border-left:0;padding-left:0}
.result-card:last-child{padding-right:0}
.result-card h3{
  font-size:var(--fs-h4);line-height:1.25;font-weight:700;
  font-variation-settings:'wdth' 106;letter-spacing:-.01em;margin:0 0 4px;
}
.result-card h3 span{display:block;font-family:var(--mono);font-size:var(--fs-mono-sm);font-weight:400;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin-top:6px}
.metric{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:9px 0;border-bottom:1px solid var(--line)}
.metric:first-of-type{border-top:1px solid var(--line);margin-top:12px}
.metric .cap{white-space:nowrap}
.metric .value{font-family:var(--mono);font-size:13px;color:var(--ink);font-variant-numeric:tabular-nums;text-align:right}
.result-card .note{margin:12px 0 0;border:0;background:transparent;padding:0;font-size:12.5px;line-height:1.55;color:var(--muted)}

.bars{margin-top:var(--s-5);border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:10px 0}
.bar-row{display:grid;grid-template-columns:22px minmax(0,1fr);gap:12px;align-items:center;padding:5px 0}
.bar-label{font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--muted)}
.bar-track{height:10px;background:var(--surface);border:1px solid var(--line);min-width:0}
.bar-fill{height:100%;width:0;transition:width .35s var(--ease)}
.bar-fill.a{background:var(--line-strong)}
.bar-fill.b{background:var(--deep)}
.bar-fill.c{background:var(--accent)}

.readout{
  margin:var(--s-5) 0 0;padding:16px 18px;
  background:var(--ink);color:var(--on-dark);
  font-family:var(--mono);font-size:12px;line-height:1.75;letter-spacing:.01em;
  white-space:pre-wrap;overflow-wrap:break-word;
  border:1px solid var(--ink);min-height:44px;
}
.readout:empty{display:none}

/* ── Raft (consensus) ───────────────────────────────────────── */
.gate{
  font-family:var(--mono);font-size:var(--fs-mono-sm);letter-spacing:.06em;
  line-height:1.5;padding:11px 14px;border:1px solid var(--line-strong);
  color:var(--muted);margin:0 0 var(--s-5);
}
.gate.ok{border-color:var(--deep);color:var(--deep)}
.gate.warn-gate{border-color:var(--accent-ink);color:var(--accent-ink)}
.gate.bad{border-color:var(--danger);color:var(--danger);background:rgba(161,22,15,.06)}

.inst-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:10px}
.strip{display:flex;gap:6px;flex-wrap:wrap}
.nd{
  width:24px;height:24px;display:grid;place-items:center;
  font-family:var(--mono);font-size:11px;letter-spacing:0;
  border:1px solid var(--line-strong);color:var(--ink);background:var(--paper);
  font-variant-numeric:tabular-nums;
}
.nd-leader{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.nd-dead{opacity:.38;text-decoration:line-through;border-style:dashed;background:transparent}

#graph{display:block;width:100%;max-width:520px;height:auto;margin:6px auto 0}
.ged-l{stroke:var(--line);stroke-width:.7}
.ged-l[data-cut]{stroke:var(--accent-ink);stroke-dasharray:3 3}
.ged-l[data-used]{stroke:var(--deep)}
.gfl-l{stroke:var(--accent);stroke-width:1.6;stroke-linecap:round}
.gfu-c{fill:none;stroke:var(--line-strong);stroke-width:1}
.gmk-p{fill:var(--ink)}
.glogbase{stroke:var(--line-strong);stroke-width:1}
.glog{stroke:var(--accent-ink);stroke-width:1.4;fill:none}
.glog-count{
  margin-top:4px;display:flex;align-items:baseline;gap:8px;
  font-family:var(--mono);font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums;
}

.quorum-row{display:flex;align-items:center;gap:16px;margin:18px 0 0}
.q-ring{
  width:62px;height:62px;flex:0 0 auto;position:relative;overflow:hidden;
  border:1px solid var(--line-strong);border-radius:50%;background:var(--paper);
}
/* a majority is more than half the ring — the hairline is the threshold */
.q-ring::after{content:'';position:absolute;left:0;right:0;top:50%;height:1px;background:var(--line-strong)}
.q-arc{
  position:absolute;inset:5px;border-radius:50%;
  background:conic-gradient(var(--accent) calc(var(--frac,0) * 360deg),transparent 0);
}
.quorum-row > div:last-child{min-width:0}
#q-state{font-family:var(--mono);font-size:12px;letter-spacing:.06em;color:var(--deep)}
#q-state.warn{color:var(--accent-ink)}

.stat-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  border-top:1px solid var(--ink);border-bottom:1px solid var(--line);
  margin:0 0 var(--s-5);
}
.stat{padding:14px 16px 15px;border-left:1px solid var(--line);min-width:0;display:flex;flex-direction:column;gap:5px}
.stat:first-child{border-left:0;padding-left:0}
.stat .cap{font-size:10px}
.stat .v{
  font-family:var(--mono);font-size:clamp(1.05rem,1.7vw,1.4rem);font-weight:500;
  color:var(--ink);line-height:1.1;font-variant-numeric:tabular-nums;
}
.stat-grid--inline{border-bottom:0;border-top:1px solid var(--line)}

.recovery{display:grid;grid-template-columns:auto minmax(0,1fr);gap:24px;align-items:center;margin-top:6px}
.r-big{display:flex;flex-direction:column;gap:6px}
.r-big #r-total{
  font-family:var(--mono);font-size:clamp(1.9rem,5.6vw,3.1rem);
  font-weight:500;line-height:1;color:var(--ink);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
}
.r-big .cap{color:var(--muted)}
.r-parts{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.r-part{display:flex;flex-direction:column;gap:5px;padding:10px 0 0;border-top:1px solid var(--line-strong);min-width:0}
.r-part .mono{font-size:15px}

.finding{
  margin-top:20px;padding:14px 16px;border:1px solid var(--line);
  border-left:2px solid var(--accent);background:var(--paper);
  font-size:var(--fs-small);line-height:1.6;color:var(--muted);
}
.finding b{color:var(--ink);font-weight:600}
.finding .verdict{display:block;margin-top:4px}
.cta-line{margin-top:12px;font-family:var(--mono);font-size:12px;letter-spacing:.04em;color:var(--ink)}
.cta-line a{border-bottom:1px solid var(--line-strong);color:var(--accent-ink)}
.cta-line a:hover{border-bottom-color:var(--accent-ink)}

.hist{
  display:flex;align-items:flex-end;gap:3px;height:84px;margin:14px 0 0;
  padding:6px;background:var(--paper);border:1px solid var(--line);
}
.hb{flex:1 1 0;min-height:2px;background:var(--accent);opacity:.86}
.hist-foot{margin:8px 0 0;font-family:var(--mono);font-size:var(--fs-mono-sm);letter-spacing:.04em;color:var(--muted);text-align:center}
.hist-empty{
  margin:0;padding:22px 8px;text-align:center;
  font-family:var(--mono);font-size:var(--fs-mono-sm);line-height:1.6;color:var(--muted);
}

.two-col{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-5)}
.two-col .plate{margin-bottom:0}
.kv{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:0;margin:0}
.kv dt,.kv dd{
  padding:8px 0;border-bottom:1px solid var(--line);
  font-family:var(--mono);font-size:11.5px;line-height:1.5;
}
.kv dt{color:var(--muted);letter-spacing:.04em;padding-right:14px}
.kv dd{margin:0;text-align:right;color:var(--ink);font-variant-numeric:tabular-nums;overflow-wrap:break-word}
.kv dt a{color:var(--accent-ink);border-bottom:1px solid var(--line-strong)}
.kv dt a:hover{border-bottom-color:var(--accent-ink)}

.feed{
  max-height:320px;overflow-y:auto;border:1px solid var(--line);background:var(--paper);
  padding:10px 14px;font-family:var(--mono);font-size:11.5px;line-height:1.7;
}
.feed:empty::before{
  content:'no events yet — the feed fills as the cluster runs';
  display:block;padding:22px 0;text-align:center;color:var(--muted);font-size:var(--fs-mono-sm);
}
.ev{display:grid;grid-template-columns:64px 82px minmax(0,1fr);gap:10px;padding:3px 0;border-bottom:1px solid var(--line)}
.ev-t{color:var(--muted)}
.ev-k{color:var(--ink);letter-spacing:.08em;text-transform:uppercase}
.ev-b{color:var(--muted);overflow-wrap:break-word}
.ev-recovery .ev-k{color:var(--deep)}
.ev-recovery .ev-b{color:var(--ink)}
.ev-refused .ev-k,.ev-minority .ev-k,.ev-stalled .ev-k,.ev-split .ev-k{color:var(--accent-ink)}
.ev-kill .ev-k,.ev-violation .ev-k,.ev-violation .ev-b{color:var(--danger)}
.ev-boot .ev-k,.ev-tempo .ev-k,.ev-adaptive .ev-k,.ev-fallback .ev-k{color:var(--accent-ink)}

/* ── Stage (cicada) ─────────────────────────────────────────── */
.stage{
  position:relative;width:100%;height:min(62vh,520px);
  background:var(--ink);border:1px solid var(--ink);overflow:hidden;touch-action:none;
}
.stage canvas{display:block;width:100%;height:100%;cursor:grab}
.stage canvas:active{cursor:grabbing}
.stage__hud{
  position:absolute;top:12px;left:14px;pointer-events:none;
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--on-dark-muted);
}
.stage__hud b{color:var(--accent);font-weight:500}
.stage__hint{
  position:absolute;bottom:12px;right:14px;pointer-events:none;
  font-family:var(--mono);font-size:var(--fs-mono-sm);letter-spacing:.06em;
  text-transform:uppercase;color:var(--on-dark-muted);
}
.stage__empty{
  position:absolute;inset:0;display:none;place-items:center;padding:24px;
  font-family:var(--mono);font-size:var(--fs-mono-sm);line-height:1.6;
  text-align:center;color:var(--on-dark-muted);
}
/* the failure message only exists once the boot catch writes it */
.stage__empty:not(:empty){display:grid}

.control-panel{
  display:flex;flex-wrap:wrap;gap:14px 26px;align-items:center;
  margin-top:var(--s-5);padding:16px 18px;
  border:1px solid var(--line);background:var(--surface);
}
.control-panel label{
  display:flex;align-items:center;gap:9px;cursor:pointer;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);
}
.control-panel input[type="range"]{width:150px;accent-color:var(--accent-ink)}
.control-panel input[type="checkbox"]{width:16px;height:16px;accent-color:var(--accent-ink)}
.control-panel .val{
  display:inline-block;min-width:2.2em;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:0;
}
.control-panel .views{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.control-panel .views > .cap{margin-right:2px}
.view-btn{
  font-family:var(--mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  padding:7px 11px;min-height:38px;border:1px solid var(--line-strong);color:var(--muted);
  transition:color .18s var(--ease),border-color .18s var(--ease),background-color .18s var(--ease);
}
.view-btn:hover{color:var(--ink);border-color:var(--ink)}
.view-btn[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--on-dark)}

/* ── Responsive — last, widest first ────────────────────────── */
@media (max-width:1024px){
  .chat{grid-template-columns:minmax(0,1fr) 268px}
  .results-grid{grid-template-columns:1fr;border-bottom:0}
  .result-card{border-left:0;padding-left:0;padding-right:0;border-bottom:1px solid var(--line)}
  .result-card:last-child{border-bottom:0}
  .recovery{grid-template-columns:1fr;gap:16px}
  .two-col{grid-template-columns:1fr}
}

@media (max-width:900px){
  .chat{grid-template-columns:1fr}
  .chat__main{border-right:0;border-bottom:1px solid var(--line)}
  .chat__log{height:clamp(260px,42vh,360px)}
  .rail-block{padding:14px 16px}
  .r-parts{grid-template-columns:repeat(3,minmax(0,1fr))}
}

@media (max-width:760px){
  .plate__head{padding:12px 14px}
  .plate__body{padding:14px}
  .plate__foot{padding:11px 14px}
  .chat__log{height:clamp(240px,40vh,320px);padding:14px}
  .message{max-width:100%}
  .chat__form{flex-wrap:wrap;padding:12px 14px}
  .chat__form .input{flex:1 1 100%}
  .chat__form .run-btn{flex:1 1 100%}
  .bench-controls{gap:12px}
  .bench-field{flex:1 1 100%}
  .bench-field .select{flex:1 1 auto;width:100%}
  .controls .run-btn,.controls .ghost-btn{flex:1 1 auto}
  .stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .stat{padding:12px 12px 13px}
  .stat:nth-child(odd){border-left:0;padding-left:0}
  .stat:nth-child(n+3){border-top:1px solid var(--line)}
  .r-parts{grid-template-columns:1fr}
  .r-big #r-total{font-size:clamp(1.8rem,9vw,2.6rem)}
  .ev{grid-template-columns:54px 70px minmax(0,1fr);gap:8px}
  .kv{grid-template-columns:1fr}
  .kv dt{border-bottom:0;padding-bottom:0}
  .kv dd{text-align:left;padding-top:0}
  .control-panel{gap:12px 18px;padding:14px}
  .control-panel input[type="range"]{width:120px}
  .stage{height:min(54vh,380px)}
  .readout{padding:13px 14px;font-size:11.5px}
}
