@dimi-agent/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/main.mjs +412209 -0
- package/dist-web/assets/CodeBlockNode-BL_lWHk1.js +28 -0
- package/dist-web/assets/DesignSystemView-Gp4T3sr4.js +13 -0
- package/dist-web/assets/DesignSystemView-VV_44Ep3.css +1 -0
- package/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist-web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist-web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist-web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist-web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist-web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist-web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist-web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist-web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist-web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist-web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist-web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist-web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist-web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist-web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist-web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist-web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist-web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist-web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist-web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist-web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist-web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist-web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist-web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist-web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist-web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist-web/assets/Tooltip-DsL7mF2H.js +1 -0
- package/dist-web/assets/__vite-optional-peer-dep_stream-diffs_markstream-vue-BIHI7g3E.js +1 -0
- package/dist-web/assets/arc-CWKkAytd.js +1 -0
- package/dist-web/assets/arc-Doj0wRZ0.js +1 -0
- package/dist-web/assets/architectureDiagram-3BPJPVTR-BxQA87W8.js +36 -0
- package/dist-web/assets/architectureDiagram-3BPJPVTR-CQ09RrbH.js +36 -0
- package/dist-web/assets/blockDiagram-GPEHLZMM-Bv-uKykJ.js +132 -0
- package/dist-web/assets/blockDiagram-GPEHLZMM-CAtDjkJt.js +132 -0
- package/dist-web/assets/c4Diagram-AAUBKEIU-BNwMmBwW.js +10 -0
- package/dist-web/assets/c4Diagram-AAUBKEIU-DtzacMnD.js +10 -0
- package/dist-web/assets/channel-B2QvGyDT.js +1 -0
- package/dist-web/assets/channel-DNkUo9e6.js +1 -0
- package/dist-web/assets/chunk-2J33WTMH-D0o9LNEb.js +1 -0
- package/dist-web/assets/chunk-2J33WTMH-w4sdiKFO.js +1 -0
- package/dist-web/assets/chunk-4BX2VUAB-C9DEPDT4.js +1 -0
- package/dist-web/assets/chunk-4BX2VUAB-WqrE2gaw.js +1 -0
- package/dist-web/assets/chunk-55IACEB6-B5dE1-Um.js +1 -0
- package/dist-web/assets/chunk-55IACEB6-DM4XnM9f.js +1 -0
- package/dist-web/assets/chunk-727SXJPM-Dky6n2gf.js +206 -0
- package/dist-web/assets/chunk-727SXJPM-Dn5wkDO_.js +206 -0
- package/dist-web/assets/chunk-AQP2D5EJ-DjmnKhuo.js +231 -0
- package/dist-web/assets/chunk-AQP2D5EJ-FS8-f8lF.js +231 -0
- package/dist-web/assets/chunk-FMBD7UC4-B2zs_Y-d.js +15 -0
- package/dist-web/assets/chunk-FMBD7UC4-wkNtOdUv.js +15 -0
- package/dist-web/assets/chunk-ND2GUHAM-Byh5s8MO.js +1 -0
- package/dist-web/assets/chunk-ND2GUHAM-C4-rwdcv.js +1 -0
- package/dist-web/assets/chunk-QZHKN3VN-C596rHAe.js +1 -0
- package/dist-web/assets/chunk-QZHKN3VN-_Rz9_NuS.js +1 -0
- package/dist-web/assets/classDiagram-4FO5ZUOK-B1ZO8EbE.js +1 -0
- package/dist-web/assets/classDiagram-4FO5ZUOK-Cc_V2QfH.js +1 -0
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B1ZO8EbE.js +1 -0
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-Cc_V2QfH.js +1 -0
- package/dist-web/assets/cose-bilkent-S5V4N54A-B5CIST3j.js +1 -0
- package/dist-web/assets/cose-bilkent-S5V4N54A-Bi19n8m-.js +1 -0
- package/dist-web/assets/cytoscape.esm-nFXppDBa.js +331 -0
- package/dist-web/assets/d2_markstream-vue-yoD6TSFD.js +1 -0
- package/dist-web/assets/dagre-BM42HDAG-DLMfLCoV.js +4 -0
- package/dist-web/assets/dagre-BM42HDAG-DQ2h_HWV.js +4 -0
- package/dist-web/assets/defaultLocale-CCNgq9ws.js +1 -0
- package/dist-web/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist-web/assets/diagram-2AECGRRQ-DQTst0OH.js +43 -0
- package/dist-web/assets/diagram-2AECGRRQ-DcJgQFHi.js +43 -0
- package/dist-web/assets/diagram-5GNKFQAL-CHeEjhiL.js +10 -0
- package/dist-web/assets/diagram-5GNKFQAL-DoE6q7H1.js +10 -0
- package/dist-web/assets/diagram-KO2AKTUF-CCF3txiw.js +3 -0
- package/dist-web/assets/diagram-KO2AKTUF-CFQs13i5.js +3 -0
- package/dist-web/assets/diagram-LMA3HP47-B5_nRmtD.js +24 -0
- package/dist-web/assets/diagram-LMA3HP47-He5zlyMt.js +24 -0
- package/dist-web/assets/diagram-OG6HWLK6-BdSBNBYS.js +24 -0
- package/dist-web/assets/diagram-OG6HWLK6-DRyxjFMa.js +24 -0
- package/dist-web/assets/erDiagram-TEJ5UH35-CZ1Ubm9Y.js +85 -0
- package/dist-web/assets/erDiagram-TEJ5UH35-yd6SOv_7.js +85 -0
- package/dist-web/assets/extended-p72mFE2C.js +1 -0
- package/dist-web/assets/floating-ui.dom-xGUaHE3m.js +1 -0
- package/dist-web/assets/flowDiagram-I6XJVG4X-C6eXPlWY.js +162 -0
- package/dist-web/assets/flowDiagram-I6XJVG4X-DkYNQv0R.js +162 -0
- package/dist-web/assets/ganttDiagram-6RSMTGT7-Cg1TQBc0.js +292 -0
- package/dist-web/assets/ganttDiagram-6RSMTGT7-LvGiqVrM.js +292 -0
- package/dist-web/assets/gitGraphDiagram-PVQCEYII-D1ktH7c_.js +106 -0
- package/dist-web/assets/gitGraphDiagram-PVQCEYII-DMbTATyw.js +106 -0
- package/dist-web/assets/graph--OzhPTMs.js +1 -0
- package/dist-web/assets/graph-BwjfAU3j.js +1 -0
- package/dist-web/assets/index-CXz8XYk1.css +1 -0
- package/dist-web/assets/index-DKIJmNQn.js +337 -0
- package/dist-web/assets/index10-ePz6DAnA.js +2 -0
- package/dist-web/assets/index11-wd1P4PGw.js +8 -0
- package/dist-web/assets/index5-D_56m6HR.js +1 -0
- package/dist-web/assets/index6-BiWLUsB3.js +1 -0
- package/dist-web/assets/index7-DSRe_h5d.js +1 -0
- package/dist-web/assets/index8-C0MfrVDC.js +1 -0
- package/dist-web/assets/infoDiagram-5YYISTIA-2JF3XEdD.js +2 -0
- package/dist-web/assets/infoDiagram-5YYISTIA-C0KiosmZ.js +2 -0
- package/dist-web/assets/init-Gi6I4Gst.js +1 -0
- package/dist-web/assets/inter-cyrillic-ext-opsz-italic-fe11NjBs.woff2 +0 -0
- package/dist-web/assets/inter-cyrillic-ext-opsz-normal-CfYZpDVp.woff2 +0 -0
- package/dist-web/assets/inter-cyrillic-opsz-italic-Ck9oD2H0.woff2 +0 -0
- package/dist-web/assets/inter-cyrillic-opsz-normal-BFQXbQ-f.woff2 +0 -0
- package/dist-web/assets/inter-greek-ext-opsz-italic-BIcRYUEt.woff2 +0 -0
- package/dist-web/assets/inter-greek-ext-opsz-normal-BmPQvyvo.woff2 +0 -0
- package/dist-web/assets/inter-greek-opsz-italic-mtaF_0H_.woff2 +0 -0
- package/dist-web/assets/inter-greek-opsz-normal-BM0NlUE_.woff2 +0 -0
- package/dist-web/assets/inter-latin-ext-opsz-italic-BLMf5All.woff2 +0 -0
- package/dist-web/assets/inter-latin-ext-opsz-normal-DpK-iCPk.woff2 +0 -0
- package/dist-web/assets/inter-latin-opsz-italic-BbqH_2Ar.woff2 +0 -0
- package/dist-web/assets/inter-latin-opsz-normal-BwkfbSeq.woff2 +0 -0
- package/dist-web/assets/inter-vietnamese-opsz-italic-C7TReJrb.woff2 +0 -0
- package/dist-web/assets/inter-vietnamese-opsz-normal-Ci9T9ieq.woff2 +0 -0
- package/dist-web/assets/ishikawaDiagram-YF4QCWOH-C5OstRVV.js +70 -0
- package/dist-web/assets/ishikawaDiagram-YF4QCWOH-CGUCgDXm.js +70 -0
- package/dist-web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist-web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist-web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist-web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist-web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist-web/assets/journeyDiagram-JHISSGLW-K-24gGZU.js +139 -0
- package/dist-web/assets/journeyDiagram-JHISSGLW-yctdo4bX.js +139 -0
- package/dist-web/assets/kanban-definition-UN3LZRKU-CxBCv27E.js +89 -0
- package/dist-web/assets/kanban-definition-UN3LZRKU-DDKuz_xA.js +89 -0
- package/dist-web/assets/katex-DnlPpQZa.js +257 -0
- package/dist-web/assets/katex-HP8lGamR.js +257 -0
- package/dist-web/assets/katexRenderer.worker-CO_gEm4q.js +257 -0
- package/dist-web/assets/layout-C1ojF0zw.js +1 -0
- package/dist-web/assets/layout-SsrduOYp.js +1 -0
- package/dist-web/assets/linear-3mB6q2-g.js +1 -0
- package/dist-web/assets/linear-DYKn_u2q.js +1 -0
- package/dist-web/assets/mermaid.core-oS_owI3c.js +309 -0
- package/dist-web/assets/mermaidParser.worker-Dx4jPi9z.js +313 -0
- package/dist-web/assets/mhchem-DtR62fUK.js +1 -0
- package/dist-web/assets/mindmap-definition-RKZ34NQL-BmJZpjh6.js +96 -0
- package/dist-web/assets/mindmap-definition-RKZ34NQL-C0lJUdai.js +96 -0
- package/dist-web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist-web/assets/pieDiagram-4H26LBE5-BkwDAvbt.js +30 -0
- package/dist-web/assets/pieDiagram-4H26LBE5-DGCPaNkB.js +30 -0
- package/dist-web/assets/quadrantDiagram-W4KKPZXB-B3op7xS9.js +7 -0
- package/dist-web/assets/quadrantDiagram-W4KKPZXB-BmT_qM09.js +7 -0
- package/dist-web/assets/requirementDiagram-4Y6WPE33-CZrxH1Y2.js +84 -0
- package/dist-web/assets/requirementDiagram-4Y6WPE33-xbfEgwL_.js +84 -0
- package/dist-web/assets/safeRaf-DGuzXxDK.js +1 -0
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-3ff_V2pD.js +40 -0
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-De_o7hDr.js +40 -0
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-C5YRTKoy.js +162 -0
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-VAxffBe7.js +162 -0
- package/dist-web/assets/stateDiagram-AJRCARHV-ltBPYPwO.js +1 -0
- package/dist-web/assets/stateDiagram-AJRCARHV-nDExQydZ.js +1 -0
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BzwD_BIl.js +1 -0
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-Dl6LC5u9.js +1 -0
- package/dist-web/assets/timeline-definition-PNZ67QCA-BT-5Wtvy.js +120 -0
- package/dist-web/assets/timeline-definition-PNZ67QCA-DsVZdrZa.js +120 -0
- package/dist-web/assets/vennDiagram-CIIHVFJN-BBHQmCFf.js +34 -0
- package/dist-web/assets/vennDiagram-CIIHVFJN-Tif-M9Km.js +34 -0
- package/dist-web/assets/vue.runtime.esm-bundler-BMrzHc_f.js +5 -0
- package/dist-web/assets/wardley-L42UT6IY-BJFn8eDD.js +173 -0
- package/dist-web/assets/wardley-L42UT6IY-CqiBaH6C.js +173 -0
- package/dist-web/assets/wardleyDiagram-YWT4CUSO-DCiyDQNB.js +78 -0
- package/dist-web/assets/wardleyDiagram-YWT4CUSO-DfgCjyaL.js +78 -0
- package/dist-web/assets/xychartDiagram-2RQKCTM6-DTwp2FCG.js +7 -0
- package/dist-web/assets/xychartDiagram-2RQKCTM6-Db_VoDBV.js +7 -0
- package/dist-web/boot.js +10 -0
- package/dist-web/favicon.ico +0 -0
- package/dist-web/index.html +23 -0
- package/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
- package/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/package.json +108 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{M as w,aD as y,aI as x,aL as c,u as s,v as t,G as d,H as o,F as r,aX as u,bb as b,I as k,cx as C,bk as z,cy as q,cz as S}from"./index-DKIJmNQn.js";const T={class:"ds-page"},B={class:"layout"},A={class:"content"},I={class:"content-inner"},M={id:"tokens"},D={class:"icon-sizes"},H={class:"sz"},L={class:"p-ic",style:{width:"14px",height:"14px"},viewBox:"0 0 24 24",fill:"currentColor"},V={class:"sz"},U={class:"p-ic",style:{width:"16px",height:"16px"},viewBox:"0 0 24 24",fill:"currentColor"},W={class:"sz"},P={class:"p-ic",style:{width:"20px",height:"20px"},viewBox:"0 0 24 24",fill:"currentColor"},R={class:"icon-grid"},N={class:"icon-group-label"},O={class:"ic-name"},j={id:"primitives"},E={class:"stage-wrap"},F={class:"stage p col"},_={class:"demo-row"},K={class:"p-btn primary disabled"},G={class:"p-spinner sm",viewBox:"0 0 24 24",style:{"--p-accent":"#fff","--p-line":"rgba(255,255,255,.35)"}},J={class:"stage-wrap"},Q={class:"stage p col",style:{gap:"0",background:"var(--p-surface)",padding:"0","max-width":"300px","align-items":"stretch"}},Y={style:{display:"flex","align-items":"center",gap:"8px",padding:"7px 10px",margin:"1px 6px","border-radius":"8px",color:"var(--p-text)","font-size":"13px"}},X={style:{color:"var(--d-fg-faint)",flex:"none"},width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor"},Z={style:{display:"flex","align-items":"center",gap:"8px",padding:"7px 10px",margin:"1px 6px","border-radius":"8px",color:"var(--p-text)","font-size":"13px"}},$={style:{color:"var(--d-fg-faint)",flex:"none"},width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor"},aa={id:"chat"},ta={class:"stage-wrap"},ca={class:"stage p col",style:{"align-items":"center",background:"#fff"}},sa={class:"demo-chat"},da={class:"p-action"},ea={class:"p-action-head"},oa={class:"p-ic",style:{color:"var(--p-accent)"},viewBox:"0 0 24 24",fill:"currentColor"},ia={class:"p-action warn"},la={class:"p-action-head"},na={class:"p-ic",style:{color:"var(--p-warning)"},viewBox:"0 0 24 24",fill:"currentColor"},va=w({__name:"DesignSystemView",emits:["close"],setup(ra,{emit:g}){const m=g;function f(){m("close")}let v=null;function p(n){n.key==="Escape"&&f()}return y(()=>{document.addEventListener("keydown",p);const n=Array.prototype.slice.call(document.querySelectorAll('#nav a[href^="#"]')),a=new Map;n.forEach(l=>{const e=l.getAttribute("href");if(!e)return;const h=document.getElementById(e.slice(1));h&&a.set(h,l)});let i=null;v=new IntersectionObserver(l=>{l.forEach(e=>{e.isIntersecting&&(i&&i.classList.remove("active"),i=a.get(e.target)??null,i&&i.classList.add("active"))})},{rootMargin:"-20% 0px -70% 0px",threshold:0}),a.forEach((l,e)=>v.observe(e)),n.length&&n[0].classList.add("active")}),x(()=>{document.removeEventListener("keydown",p),v&&(v.disconnect(),v=null)}),(n,a)=>(c(),s("div",T,[t("div",{class:"ds-topbar"},[t("button",{class:"ds-back",type:"button",onClick:f},"← Back"),a[0]||(a[0]=t("span",{class:"ds-topbar-title"},"Design system",-1))]),t("div",B,[a[38]||(a[38]=d('<aside class="sidebar" data-v-6c48fca3><div class="brand" data-v-6c48fca3><div class="brand-mark" data-v-6c48fca3>K</div><div class="brand-name" data-v-6c48fca3>Dimi Web</div></div><div class="brand-sub" data-v-6c48fca3>Design System · v1.0</div><div class="nav-group" data-v-6c48fca3>Navigate</div><nav class="nav" id="nav" data-v-6c48fca3><a href="#overview" data-v-6c48fca3><span class="num" data-v-6c48fca3>00</span>Overview</a><a href="#principles" data-v-6c48fca3><span class="num" data-v-6c48fca3>01</span>Design Principles</a><a href="#tokens" data-v-6c48fca3><span class="num" data-v-6c48fca3>02</span>Design Tokens</a><a href="#primitives" data-v-6c48fca3><span class="num" data-v-6c48fca3>03</span>Primitives</a><a href="#chat" data-v-6c48fca3><span class="num" data-v-6c48fca3>04</span>Chat Interface</a><a href="#themes" data-v-6c48fca3><span class="num" data-v-6c48fca3>05</span>Theming</a><a href="#rules" data-v-6c48fca3><span class="num" data-v-6c48fca3>06</span>Style Rules</a><a href="#shell" data-v-6c48fca3><span class="num" data-v-6c48fca3>07</span>App Shell & Sidebar</a><a href="#a11y" data-v-6c48fca3><span class="num" data-v-6c48fca3>08</span>Accessibility</a></nav><div class="nav-group" data-v-6c48fca3>Companion output</div><nav class="nav" data-v-6c48fca3><a href="#tokens" data-v-6c48fca3><span class="num" data-v-6c48fca3>↗</span>Token list</a><a href="#primitives" data-v-6c48fca3><span class="num" data-v-6c48fca3>↗</span>Component API</a><a href="#rules" data-v-6c48fca3><span class="num" data-v-6c48fca3>↗</span>Style rules</a></nav></aside>',1)),t("main",A,[t("div",I,[a[36]||(a[36]=d('<section id="overview" data-v-6c48fca3><div class="hero" data-v-6c48fca3><span class="eyebrow" data-v-6c48fca3>● Design System · v1.0</span><h1 data-v-6c48fca3>Dimi Web <span class="grad" data-v-6c48fca3>Design System</span></h1><p class="lead" data-v-6c48fca3> This document defines the visual language and component specification for Dimi Web — design tokens, component primitives, the chat interface, theming, and style rules. All UI work is grounded in it: unified, restrained, token-driven, and themeable. </p><div class="hero-meta" data-v-6c48fca3><span class="meta-chip" data-v-6c48fca3><span class="dot" data-v-6c48fca3></span> Scope <b data-v-6c48fca3>apps/dimi-web</b></span><span class="meta-chip" data-v-6c48fca3>Component primitives</span><span class="meta-chip" data-v-6c48fca3>Theme <b data-v-6c48fca3>1 set · 4 customizable colors</b></span><span class="meta-chip" data-v-6c48fca3>Light / dark mode</span></div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>This spec is the single reference when changing the web UI.</b> Before adding or modifying a component, style, layout, or theme, read this document first; color, font, radius, spacing, shadow, z-index, and motion always use the §02 tokens, components reuse the §03 primitives, and the §06 style rules are followed. </div></div></section><section id="principles" data-v-6c48fca3><div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>01</span><h2 class="sec-title" data-v-6c48fca3>Design Principles</h2></div><p class="sec-desc" data-v-6c48fca3> Every UI decision traces back to the following principles. Dimi Web is a local Agent tool for developers: quick scanning, long stretches of staring, often in the dark — the design serves the task, and is restrained, clinical, and density-first. </p><ul class="clean check" data-v-6c48fca3><li data-v-6c48fca3><b data-v-6c48fca3>Consistency</b> —— The same semantics use the same component. The primary button, dialog, input, and badge should each have exactly "one" correct way to be written across the entire site.</li><li data-v-6c48fca3><b data-v-6c48fca3>Hierarchy</b> —— Build a clear hierarchy through size, weight, color, and whitespace; emphasize through "restraint" rather than "bolder and bigger".</li><li data-v-6c48fca3><b data-v-6c48fca3>Proximity</b> —— Group related elements, leave whitespace between unrelated ones. A card's padding, line spacing, and group spacing all come from the same spacing scale.</li><li data-v-6c48fca3><b data-v-6c48fca3>Feedback</b> —— hover / active / focus / loading / success / error all have visible states, and the state language is unified.</li><li data-v-6c48fca3><b data-v-6c48fca3>Breathing room</b> —— Control density with the spacing scale rather than arbitrary pixels; prefer restrained whitespace over cramming controls together.</li><li data-v-6c48fca3><b data-v-6c48fca3>Accessibility (A11y)</b> —— Text contrast ≥ 4.5:1, visible focus rings, touch targets ≥ 32px, and states that don't rely on color alone.</li><li data-v-6c48fca3><b data-v-6c48fca3>Reduction</b> —— The number of colors, radii, shadow levels, and type sizes all converge to a finite set of tokens; delete stray values.</li></ul><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3><b data-v-6c48fca3>Brand tone (the do-not list)</b>: calm, clinical, never exaggerated. <span class="pill red" style="margin:0 4px;" data-v-6c48fca3>Reject</span> purple gradients, glassmorphism, glowing shadows, AI purple / blue glows, endlessly looping fussy micro-animations, "Boost your productivity"-style marketing copy, and using emoji as icons — <b data-v-6c48fca3>the moon phases 🌑…🌘 are the sole exception</b>, used only in the "waiting for the Agent to respond" chat state, as a brand signature. These are all common tells of AI-generated interfaces (an "AI tell"), deliberately avoided. </div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>Declare design intent first (Design Read)</b>: before adding a component / page, write one sentence describing its scenario, audience, and tone (for example, "a lightweight tool card embedded in a conversation, for developers, calm and restrained"), then build. If the intent isn't clear, ask one question first rather than defaulting to the nearest existing style. </div></div></section>',2)),t("section",M,[a[7]||(a[7]=d(`<div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>02</span><h2 class="sec-title" data-v-6c48fca3>Design Tokens</h2></div><p class="sec-desc" data-v-6c48fca3> Collapse every visual decision into tokens. <b data-v-6c48fca3>Color tokens keep the existing short names and fill out the semantics</b> (lowering migration cost), while <b data-v-6c48fca3>spacing, z-index, motion, and font-weight</b> fill in the scales that are currently missing. Every token has: name, light value, dark value, and usage. </p><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>Naming convention</b>: <code data-v-6c48fca3>--<category>-<role>-<state></code>. For example <code data-v-6c48fca3>--color-text-muted</code>, <code data-v-6c48fca3>--radius-md</code>, <code data-v-6c48fca3>--space-4</code>. To reduce churn, the existing short names (<code data-v-6c48fca3>--bg</code> / <code data-v-6c48fca3>--ink</code> / <code data-v-6c48fca3>--line</code> / <code data-v-6c48fca3>--blue</code> …) are kept as <b data-v-6c48fca3>compatibility aliases</b> for one release cycle. </div></div><h3 class="sub" data-v-6c48fca3>Color</h3><p data-v-6c48fca3>Semantic-first, in three layers: <b data-v-6c48fca3>background / text / border</b> + <b data-v-6c48fca3>accent</b> + <b data-v-6c48fca3>status colors</b>. All colors are defined in light / dark pairs, with contrast ≥ 4.5:1.</p><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3>The table below shows the <b data-v-6c48fca3>derived semantic tokens</b>. The <b data-v-6c48fca3>neutrals and the accent</b> are derived from the 4 color seeds in §05 — for example <code data-v-6c48fca3>--color-accent</code> comes from <code data-v-6c48fca3>--accent-primary</code>, and <code data-v-6c48fca3>--color-bg</code> comes from the current light / dark surface. The <b data-v-6c48fca3>semantic status colors</b> (success / warning / danger / info) are independent palettes paired with the seeds, one set each for light / dark; they are not auto-derived from the seeds. Day-to-day reskinning usually only needs the 4 seeds, with the status colors fine-tuned as needed.</div></div><div class="palette" data-v-6c48fca3><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#ffffff;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>bg</div><div class="cv" data-v-6c48fca3>#ffffff / #0d1117</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#fafbfc;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>surface</div><div class="cv" data-v-6c48fca3>#fafbfc / #161b22</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#f3f5f8;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>surface-sunken</div><div class="cv" data-v-6c48fca3>#f3f5f8 / #0d1117</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#eceff3;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>selected</div><div class="cv" data-v-6c48fca3>#eceff3 / #2d333b</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#14171c;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>fg</div><div class="cv" data-v-6c48fca3>#14171c / #e8eaed</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#6b7280;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>fg-muted</div><div class="cv" data-v-6c48fca3>#6b7280 / #9aa0a8</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#e7eaee;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>line</div><div class="cv" data-v-6c48fca3>#e7eaee / #2d333b</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#1783ff;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>accent (KMBlue)</div><div class="cv" data-v-6c48fca3>#1783ff / #58a6ff</div></div></div><div class="color-card" data-v-6c48fca3><div class="color-chip" style="background:#e8f3ff;" data-v-6c48fca3></div><div class="color-meta" data-v-6c48fca3><div class="cn" data-v-6c48fca3>accent-soft</div><div class="cv" data-v-6c48fca3>#e8f3ff / rgba(88,166,255,.14)</div></div></div></div><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Light</th><th data-v-6c48fca3>Dark</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-bg</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fff;" data-v-6c48fca3></span>#ffffff</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#0d1117;" data-v-6c48fca3></span>#0d1117</td><td data-v-6c48fca3>Page background</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-surface</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fafbfc;" data-v-6c48fca3></span>#fafbfc</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#161b22;" data-v-6c48fca3></span>#161b22</td><td data-v-6c48fca3>Panel / sidebar / card head</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-surface-raised</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fff;" data-v-6c48fca3></span>#ffffff</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#1c2128;" data-v-6c48fca3></span>#1c2128</td><td data-v-6c48fca3>Raised card / dialog / input</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-text</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#14171c;" data-v-6c48fca3></span>#14171c</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#e8eaed;" data-v-6c48fca3></span>#e8eaed</td><td data-v-6c48fca3>Body text / headings</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-text-muted</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#6b7280;" data-v-6c48fca3></span>#6b7280</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#9aa0a8;" data-v-6c48fca3></span>#9aa0a8</td><td data-v-6c48fca3>Secondary text / placeholder</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-line</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#e7eaee;" data-v-6c48fca3></span>#e7eaee</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#2d333b;" data-v-6c48fca3></span>#2d333b</td><td data-v-6c48fca3>Divider / card border</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-selected</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#00000014;" data-v-6c48fca3></span>#00000014</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#ffffff14;" data-v-6c48fca3></span>#ffffff14</td><td data-v-6c48fca3>Neutral selected fill (sidebar rows, list pickers) — translucent, never accent-tinted</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-hover</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#0000000d;" data-v-6c48fca3></span>#0000000d</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#ffffff0d;" data-v-6c48fca3></span>#ffffff0d</td><td data-v-6c48fca3>Row hover wash — lighter than the selected fill (hover < selected); translucent, sits on any surface</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-media-alpha-bg-1</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#858585;" data-v-6c48fca3></span>≈#858585</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#676b72;" data-v-6c48fca3></span>≈#676b72</td><td data-v-6c48fca3>Checkerboard square A of the <code data-v-6c48fca3><img></code> alpha canvas — color-mix of <code data-v-6c48fca3>--color-bg</code>/<code data-v-6c48fca3>--color-text</code> (52/48); applied via <code data-v-6c48fca3>--media-alpha-canvas</code> (16px period)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-media-alpha-bg-2</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#6b6b6b;" data-v-6c48fca3></span>≈#6b6b6b</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#7a7e85;" data-v-6c48fca3></span>≈#7a7e85</td><td data-v-6c48fca3>Checkerboard square B (42/58) — both squares stay ≥3:1 against white and black; opaque images cover the canvas</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-sidebar-bg</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fbfaf9;" data-v-6c48fca3></span>#fbfaf9</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#181817;" data-v-6c48fca3></span>#181817</td><td data-v-6c48fca3>Sidebar surface — one step off <code data-v-6c48fca3>--color-bg</code> so the session column reads as its own plane</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-accent</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#1783ff;" data-v-6c48fca3></span>#1783ff</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#58a6ff;" data-v-6c48fca3></span>#58a6ff</td><td data-v-6c48fca3>Primary action / link / focus</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-success</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#0e7a38;" data-v-6c48fca3></span>#0e7a38</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#3fb950;" data-v-6c48fca3></span>#3fb950</td><td data-v-6c48fca3>Success / pass</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-warning</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#a9610a;" data-v-6c48fca3></span>#a9610a</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#d29922;" data-v-6c48fca3></span>#d29922</td><td data-v-6c48fca3>Warning / pending</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--color-danger</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#c0392b;" data-v-6c48fca3></span>#c0392b</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#f85149;" data-v-6c48fca3></span>#f85149</td><td data-v-6c48fca3>Danger / error / abort</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Surface usage</h4><p data-v-6c48fca3>The four surface layers each have a role — choose by "raised layer / default flat layer / sunken layer / page background", and avoid treating <code data-v-6c48fca3>--p-surface-raised</code> as a universal background.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Light</th><th data-v-6c48fca3>Dark</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-surface-raised</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fff;" data-v-6c48fca3></span>#ffffff</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#1c2128;" data-v-6c48fca3></span>#1c2128</td><td data-v-6c48fca3>Raised card / dialog / input (raised layer)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-surface</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fafbfc;" data-v-6c48fca3></span>#fafbfc</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#161b22;" data-v-6c48fca3></span>#161b22</td><td data-v-6c48fca3>Panel / sidebar / card head (default flat layer)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-surface-sunken</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#f3f5f8;" data-v-6c48fca3></span>#f3f5f8</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#0d1117;" data-v-6c48fca3></span>#0d1117</td><td data-v-6c48fca3>Code block / inline input / recessed area (sunken layer)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-bg</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#fff;" data-v-6c48fca3></span>#ffffff</td><td class="val" data-v-6c48fca3><span class="swatch" style="background:#0d1117;" data-v-6c48fca3></span>#0d1117</td><td data-v-6c48fca3>Page background</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Focus ring</h4><p data-v-6c48fca3>All focusable controls (button, input, link, menu item, switch, checkbox) use the focus-ring token uniformly; do not hand-write a <code data-v-6c48fca3>box-shadow</code> focus ring.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-focus-ring</td><td class="val" data-v-6c48fca3>0 0 0 3px var(--p-accent-soft)</td><td data-v-6c48fca3>Default focus ring (link, menu item, switch, checkbox)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-focus-ring-strong</td><td class="val" data-v-6c48fca3>0 0 0 3px var(--p-accent-soft), 0 0 0 1px var(--p-accent)</td><td data-v-6c48fca3>Strong focus ring (button, primary action)</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Text selection</h4><p data-v-6c48fca3>The text-selection color uses <code data-v-6c48fca3>--p-selection</code> uniformly (light <code data-v-6c48fca3>rgba(23,131,255,.18)</code> / dark <code data-v-6c48fca3>rgba(88,166,255,.32)</code>), applied by the global <code data-v-6c48fca3>::selection</code> rule; do not set a separate highlight background.</p><h4 class="mini" data-v-6c48fca3>Disabled state</h4><p data-v-6c48fca3>All disabled controls use <code data-v-6c48fca3>opacity:.5</code> + <code data-v-6c48fca3>cursor:not-allowed</code> uniformly; do not separately grey out or recolor.</p><h3 class="sub" data-v-6c48fca3>Font families</h3><p data-v-6c48fca3>Dimi Web uses two font families: <b data-v-6c48fca3>--font-ui</b> (UI and body, Inter first) and <b data-v-6c48fca3>--font-mono</b> (code and monospace). Components always reference the variables; do not hard-code font names.</p><h4 class="mini" data-v-6c48fca3>--font-ui · UI & body (Inter first)</h4><p data-v-6c48fca3>Body and UI use self-hosted Inter as the primary face. CJK and platform system UI fonts sit late in the fallback chain so Latin glyphs resolve to Inter while Chinese text can fall through to native CJK fonts:</p><div class="code" data-v-6c48fca3><div class="code-bar" data-v-6c48fca3><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="fn" data-v-6c48fca3>--font-ui</span></div><pre data-v-6c48fca3>--font-ui: "Inter Variable", "Inter", "Helvetica Neue", Arial,
|
|
2
|
+
"PingFang SC", "Microsoft YaHei", "Noto Sans SC",
|
|
3
|
+
-apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
4
|
+
Roboto, Ubuntu, sans-serif,
|
|
5
|
+
"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";</pre></div><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>Inter first: self-hosted Latin UI and body text, loaded through the optical-size normal and italic variable faces.</li><li data-v-6c48fca3>Western fallbacks next: Helvetica Neue / Arial for environments where Inter cannot load.</li><li data-v-6c48fca3>CJK and system UI fallbacks late: PingFang SC / Microsoft YaHei / Noto Sans SC, then platform UI fonts and emoji fonts.</li></ul><h4 class="mini" data-v-6c48fca3>--font-mono · Code & monospace</h4><p data-v-6c48fca3>Code, tool names, line numbers, diffs, etc. use JetBrains Mono (a self-hosted variable font), falling back to the system monospace:</p><div class="code" data-v-6c48fca3><div class="code-bar" data-v-6c48fca3><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="fn" data-v-6c48fca3>--font-mono</span></div><pre data-v-6c48fca3>--font-mono: "JetBrains Mono Variable", "JetBrains Mono",
|
|
6
|
+
ui-monospace, "SF Mono", Menlo, Consolas, monospace;</pre></div><h4 class="mini" data-v-6c48fca3>Loading strategy</h4><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Font</th><th data-v-6c48fca3>Source</th><th data-v-6c48fca3>Bundled</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>JetBrains Mono</td><td class="val" data-v-6c48fca3>@fontsource-variable/jetbrains-mono</td><td class="val" data-v-6c48fca3>✓ self-hosted</td><td data-v-6c48fca3>monospace / code (--font-mono)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Inter</td><td class="val" data-v-6c48fca3>@fontsource-variable/inter/opsz.css + opsz-italic.css</td><td class="val" data-v-6c48fca3>✓ self-hosted</td><td data-v-6c48fca3>UI / body / display (--font-ui, --font-display), wght 100-900, opsz 14-32, normal + italic</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>System UI / CJK fonts</td><td class="val" data-v-6c48fca3>operating system</td><td class="val" data-v-6c48fca3>—</td><td data-v-6c48fca3>late fallback for UI / body, not bundled</td></tr></tbody></table><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3> Self-hosted Inter / JetBrains Mono: no external network requests, no FOUT, works offline; system fonts are not bundled, consistent with the local-first approach. </div></div><h4 class="mini" data-v-6c48fca3>Usage rules</h4><ul class="clean check" data-v-6c48fca3><li data-v-6c48fca3>Components always use <code data-v-6c48fca3>var(--font-ui)</code> / <code data-v-6c48fca3>var(--font-mono)</code>; do not hard-code font names like <code data-v-6c48fca3>'Inter'</code> / <code data-v-6c48fca3>'JetBrains Mono'</code>.</li><li data-v-6c48fca3>Body / UI use <code data-v-6c48fca3>--font-ui</code> (Inter first); code / monospace use <code data-v-6c48fca3>--font-mono</code> (JetBrains Mono).</li><li data-v-6c48fca3>Inter is loaded from the complete optical-size variable faces, including normal and italic styles; <code data-v-6c48fca3>font-optical-sizing: auto</code> is enabled globally.</li><li data-v-6c48fca3>CJK and platform system UI fonts stay late in the <code data-v-6c48fca3>--font-ui</code> fallback chain, after Inter and Western fallbacks.</li></ul><h3 class="sub" data-v-6c48fca3>Type scale & weight</h3><p data-v-6c48fca3>The user font-size preference writes <code data-v-6c48fca3>--base-ui-font-size</code>. Compact UI chrome and the sidebar follow it through <code data-v-6c48fca3>--ui-font-size</code>, while chat reading surfaces derive one readable step above it through <code data-v-6c48fca3>--content-font-size</code>.</p><p data-v-6c48fca3>The fixed product type tokens still define component defaults: <b data-v-6c48fca3>UI controls / buttons / forms</b> use <code data-v-6c48fca3>--text-base</code> (14px); <b data-v-6c48fca3>reading body — including chat Markdown, message bubbles, etc.</b> stays one step larger than compact chrome for readability; the <b data-v-6c48fca3>sidebar session list</b> follows that same readable step while keeping list density. Drop stray <code data-v-6c48fca3>font-weight: 650 / 750</code>; converge on two weights, 400 / 500 (regular / emphasis).</p><div class="panel panel-pad" style="margin:16px 0;" data-v-6c48fca3><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:22px;font-weight:500;" data-v-6c48fca3>Page Title</div><div class="type-meta" data-v-6c48fca3>--text-2xl · 22 / 500</div></div><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:18px;font-weight:500;" data-v-6c48fca3>Section Title</div><div class="type-meta" data-v-6c48fca3>--text-xl · 18 / 500</div></div><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:16px;font-weight:400;" data-v-6c48fca3>Chat body / card title</div><div class="type-meta" data-v-6c48fca3>--text-lg · 16 / 400</div></div><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:14px;font-weight:500;" data-v-6c48fca3>UI control / button / form</div><div class="type-meta" data-v-6c48fca3>--text-base · 14 / 500</div></div><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:13px;" data-v-6c48fca3>Helper text / table</div><div class="type-meta" data-v-6c48fca3>--text-sm · 13 / 400</div></div><div class="type-row" data-v-6c48fca3><div class="type-sample" style="font-size:12px;" data-v-6c48fca3>Badge / timestamp / line number</div><div class="type-meta" data-v-6c48fca3>--text-xs · 12 / 500</div></div></div><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--font-ui</td><td class="val" data-v-6c48fca3>"Inter Variable", "Inter", "Helvetica Neue", Arial…</td><td data-v-6c48fca3>UI & body (Inter first)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--font-mono</td><td class="val" data-v-6c48fca3>JetBrains Mono…</td><td data-v-6c48fca3>code, tool names, line numbers, diffs</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--base-ui-font-size</td><td class="val" data-v-6c48fca3>14px user preference</td><td data-v-6c48fca3>root setting that drives UI, reading body, and sidebar font sizes</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--content-font-size</td><td class="val" data-v-6c48fca3>calc(base + 1px)</td><td data-v-6c48fca3>chat Markdown, message bubbles, composer</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--leading-tight/normal/relaxed</td><td class="val" data-v-6c48fca3>1.25 / 1.5 / 1.7</td><td data-v-6c48fca3>headings / UI / long text</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--weight-regular/medium</td><td class="val" data-v-6c48fca3>400 / 500</td><td data-v-6c48fca3>body / emphasis</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Icon size</h4><p data-v-6c48fca3>Icons use three size tokens uniformly. The global <code data-v-6c48fca3>.p-ic</code> default is 16px (<code data-v-6c48fca3>--p-ic-md</code>); components pick as needed, and random pixel sizes are forbidden.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-ic-sm</td><td class="val" data-v-6c48fca3>14px</td><td data-v-6c48fca3>small button, badge, menu item, inline link icon</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-ic-md</td><td class="val" data-v-6c48fca3>16px</td><td data-v-6c48fca3>default (button, icon button, toolbar)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-ic-lg</td><td class="val" data-v-6c48fca3>20px</td><td data-v-6c48fca3>Toast status icon, empty-state illustration</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Icon</h4><p data-v-6c48fca3>Icons always come from the centralized registry <code data-v-6c48fca3>lib/icons.ts</code>: in templates use the <code data-v-6c48fca3><Icon name size /></code> component (<code data-v-6c48fca3>components/ui/Icon.vue</code>); for <code data-v-6c48fca3>v-html</code> contexts (such as a tool glyph) use <code data-v-6c48fca3>iconSvg(name, size)</code>. <b data-v-6c48fca3>Do not hand-write <code data-v-6c48fca3><svg></code></b> — the <code data-v-6c48fca3>scripts/check-style.mjs</code> <code data-v-6c48fca3>icon-from-registry</code> rule flags stray SVGs. Icons come from <a href="https://remixicon.com/" data-v-6c48fca3>Remix Icon</a> (Apache-2.0), uniformly in a fill style (<code data-v-6c48fca3>fill="currentColor"</code>, 24×24 source grid), with color following the text; size uses the three tokens below. The registry is bundled on demand by <a href="https://github.com/unplugin/unplugin-icons" data-v-6c48fca3>unplugin-icons</a> at build time from <code data-v-6c48fca3>@iconify-json/ri</code> — only icons imported in <code data-v-6c48fca3>lib/icons.ts</code> end up in the production bundle, fully offline and tree-shaken. <b data-v-6c48fca3>The whole site uses only this one icon family</b>; do not mix in other icon libraries, and <b data-v-6c48fca3>never hand-write SVG paths</b>. When an icon is missing, add it to the registry — two static <code data-v-6c48fca3>~icons/ri/*</code> imports (component + <code data-v-6c48fca3>?raw</code> string) plus one entry in <code data-v-6c48fca3>ICONS</code> in <code data-v-6c48fca3>lib/icons.ts</code>; the import names (e.g. <code data-v-6c48fca3>RiFolderOpenLine</code> / <code data-v-6c48fca3>RawFolderOpenLine</code>) show the <code data-v-6c48fca3>ri:</code> icon id. Do not draw it in a component.</p><h4 class="mini" data-v-6c48fca3>Size scale</h4>`,43)),t("div",D,[t("div",H,[(c(),s("svg",L,[...a[1]||(a[1]=[t("path",{fill:"currentColor",d:"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"},null,-1)])])),a[2]||(a[2]=o("sm · 14",-1))]),t("div",V,[(c(),s("svg",U,[...a[3]||(a[3]=[t("path",{fill:"currentColor",d:"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"},null,-1)])])),a[4]||(a[4]=o("md · 16",-1))]),t("div",W,[(c(),s("svg",P,[...a[5]||(a[5]=[t("path",{fill:"currentColor",d:"M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"},null,-1)])])),a[6]||(a[6]=o("lg · 20",-1))])]),a[8]||(a[8]=t("h4",{class:"mini"},"Icon library",-1)),a[9]||(a[9]=t("p",null,[o("Currently registered icons, grouped by purpose. The display order and grouping are defined by "),t("code",null,"ICON_GROUPS"),o(" in "),t("code",null,"lib/icons.ts"),o(" (a hand-maintained array covering the same icon names), and this catalog is rendered directly from that array so the registry and the document never drift.")],-1)),t("div",R,[(c(!0),s(r,null,u(z(q),([i,l])=>(c(),s(r,{key:i},[t("div",N,b(i),1),(c(!0),s(r,null,u(l,e=>(c(),s("div",{key:e,class:"icon-cell"},[k(C,{name:e},null,8,["name"]),t("span",O,b(e),1)]))),128))],64))),128))]),a[10]||(a[10]=d('<p data-v-6c48fca3>Do not use emoji as functional icons (the sole exception is the moon phases 🌑…🌘, used only in the "waiting for the Agent to respond" chat state). The Dimi brand mark (the 32×22 eye logo) is a brand asset and is not part of this icon system.</p><p data-v-6c48fca3>A few <b data-v-6c48fca3>special graphics</b> are not in the registry; each has a dedicated component maintained in one place, and must not be copied by hand: <code data-v-6c48fca3><ContextRing :pct /></code> (the Composer context progress ring, data-driven), <code data-v-6c48fca3><AuthStateIcon kind /></code> (the success / expired / error colored illustrations in the login flow), <code data-v-6c48fca3><Spinner /></code> (loading state). Status dots (such as in the Provider list) always use CSS dots (<code data-v-6c48fca3>border-radius:50%</code>), not SVG. The <code data-v-6c48fca3>scripts/check-style.mjs</code> <code data-v-6c48fca3>icon-from-registry</code> rule exempts the above and the brand mark; all other hand-written <code data-v-6c48fca3><svg></code> is flagged.</p><h3 class="sub" data-v-6c48fca3>Spacing</h3><p data-v-6c48fca3>A 4px base grid. All spacing, gaps, and padding inside and outside components come from this scale — no arbitrary pixels.</p><div class="panel panel-pad" style="margin:16px 0;" data-v-6c48fca3><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:4px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-1 · 4</div><div class="space-use" data-v-6c48fca3>icon gap, badge padding</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:8px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-2 · 8</div><div class="space-use" data-v-6c48fca3>control gap, small padding</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:12px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-3 · 12</div><div class="space-use" data-v-6c48fca3>button padding, form-item gap</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:16px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-4 · 16</div><div class="space-use" data-v-6c48fca3>card padding, grid gap</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:20px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-5 · 20</div><div class="space-use" data-v-6c48fca3>dialog padding</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:24px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-6 · 24</div><div class="space-use" data-v-6c48fca3>section gap</div></div><div class="space-row" data-v-6c48fca3><div class="space-bar" style="width:32px;" data-v-6c48fca3></div><div class="space-meta" data-v-6c48fca3>--space-8 · 32</div><div class="space-use" data-v-6c48fca3>large section gap</div></div></div><h4 class="mini" data-v-6c48fca3>Dense list (sidebar / file tree)</h4><p data-v-6c48fca3>High-density navigation lists like the sidebar share one rhythm, all on the 4px grid: <b data-v-6c48fca3>in-row vertical padding</b> <code data-v-6c48fca3>--space-1</code> (4px), <b data-v-6c48fca3>no margin between rows</b> (the hover pill provides the separation); <b data-v-6c48fca3>section gap</b> (between logo / search / action buttons / group title / list) uniformly <code data-v-6c48fca3>--space-2</code> (8px); <b data-v-6c48fca3>between groups</b> <code data-v-6c48fca3>--space-2</code>; the brand header is slightly looser at the top (<code data-v-6c48fca3>--space-3</code>). When building similar lists, reuse this scale — do not hand-write 1/6/7/10px.</p><h3 class="sub" data-v-6c48fca3>Radius</h3><p data-v-6c48fca3>Merge the existing 14 values <b data-v-6c48fca3>into the nearest</b> of 7 scale steps. Rule: the component type determines the radius, not the author's feel.</p><div class="radius-grid" data-v-6c48fca3><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:4px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>xs · 4</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:6px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>sm · 6</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:8px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>md · 8</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:12px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>lg · 12</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:16px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>xl · 16</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:20px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>2xl · 20</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border-radius:999px;" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>full · 999</span></div></div><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th><th data-v-6c48fca3>Merged from</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-xs</td><td class="val" data-v-6c48fca3>4px</td><td data-v-6c48fca3>small badge, inline tag</td><td class="val" data-v-6c48fca3>2/3/4px →</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-sm</td><td class="val" data-v-6c48fca3>6px</td><td data-v-6c48fca3>small button, icon button, menu item</td><td class="val" data-v-6c48fca3>5/6px →</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-md</td><td class="val" data-v-6c48fca3>8px</td><td data-v-6c48fca3>button, input, badge, card</td><td class="val" data-v-6c48fca3>7/8/9px →</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-lg</td><td class="val" data-v-6c48fca3>12px</td><td data-v-6c48fca3>dropdown panel</td><td class="val" data-v-6c48fca3>10/12px →</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-xl</td><td class="val" data-v-6c48fca3>16px</td><td data-v-6c48fca3>dialog, bottom Sheet, Composer</td><td class="val" data-v-6c48fca3>14/16px →</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-2xl</td><td class="val" data-v-6c48fca3>20px</td><td data-v-6c48fca3>accent container / large panel</td><td class="val" data-v-6c48fca3>20px</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--radius-full</td><td class="val" data-v-6c48fca3>999px</td><td data-v-6c48fca3>pill badge, avatar, send button</td><td class="val" data-v-6c48fca3>999px / 50%</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Elevation & z-index</h3><p data-v-6c48fca3>Shadows express only "elevation", never decoration (no colored glow). z-index is unified into a scale, eradicating <code data-v-6c48fca3>9999</code>-style one-upping.</p><div class="panel panel-pad" style="margin:16px 0;" data-v-6c48fca3><div class="radius-grid" style="align-items:stretch;" data-v-6c48fca3><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border:none;background:#fff;box-shadow:0 1px 2px rgba(16,24,40,.05),0 1px 3px rgba(16,24,40,.06);" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>sm · dropdown menu / sticky</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border:none;background:#fff;box-shadow:0 4px 12px rgba(16,24,40,.07),0 2px 4px rgba(16,24,40,.05);" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>md · Toast</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border:none;background:#fff;box-shadow:0 12px 32px rgba(16,24,40,.12),0 4px 10px rgba(16,24,40,.08);" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>lg · overlay (reserved)</span></div><div class="radius-item" data-v-6c48fca3><div class="radius-box" style="border:none;background:#fff;box-shadow:0 24px 64px rgba(16,24,40,.18),0 8px 20px rgba(16,24,40,.10);" data-v-6c48fca3></div><span class="rl" data-v-6c48fca3>xl · dialog</span></div></div></div><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Z-index Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-base</td><td class="val" data-v-6c48fca3>0</td><td data-v-6c48fca3>normal flow</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-sticky</td><td class="val" data-v-6c48fca3>100</td><td data-v-6c48fca3>sticky header / sidebar</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-dropdown</td><td class="val" data-v-6c48fca3>200</td><td data-v-6c48fca3>dropdown menu / tooltip</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-overlay</td><td class="val" data-v-6c48fca3>300</td><td data-v-6c48fca3>overlay / bottom Sheet</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-modal</td><td class="val" data-v-6c48fca3>400</td><td data-v-6c48fca3>dialog</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-toast</td><td class="val" data-v-6c48fca3>600</td><td data-v-6c48fca3>toast</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--z-max</td><td class="val" data-v-6c48fca3>9999</td><td data-v-6c48fca3>reserved: only this tier for extreme fallback</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Motion</h3><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--ease-out</td><td class="val" data-v-6c48fca3>cubic-bezier(0.16, 1, 0.3, 1)</td><td data-v-6c48fca3>enter, hover, expand</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--ease-in-out</td><td class="val" data-v-6c48fca3>cubic-bezier(0.4, 0, 0.2, 1)</td><td data-v-6c48fca3>panel width, layout changes</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--duration-fast</td><td class="val" data-v-6c48fca3>120ms</td><td data-v-6c48fca3>press, focus</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--duration-base</td><td class="val" data-v-6c48fca3>160ms</td><td data-v-6c48fca3>hover, show/hide</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--duration-slow</td><td class="val" data-v-6c48fca3>260ms</td><td data-v-6c48fca3>dialog, Sheet, layout</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>Reduced motion</h4><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> Under <code data-v-6c48fca3>@media (prefers-reduced-motion: reduce)</code>, all animation and transition durations drop to about <code data-v-6c48fca3>0.001ms</code> (effectively off), and the <b data-v-6c48fca3>MoonSpinner moon phase pauses</b> on the current frame. Components should not check this individually; it is handled uniformly in the global styles. </div></div><h3 class="sub" data-v-6c48fca3>Layout & breakpoints</h3><p data-v-6c48fca3>Layout sizes and responsive breakpoints are tokenized too: sidebar width, content reading-column width, and two global breakpoints. Components should not hard-code pixels.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-sidebar-w</td><td class="val" data-v-6c48fca3>264px</td><td data-v-6c48fca3>left session sidebar width</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-content-max</td><td class="val" data-v-6c48fca3>760px</td><td data-v-6c48fca3>chat reading-column max width (regular chat prose)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-content-wide</td><td class="val" data-v-6c48fca3>920px</td><td data-v-6c48fca3>wide content (settings / panel)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-table-max</td><td class="val" data-v-6c48fca3>1040px</td><td data-v-6c48fca3>desktop wide-table max width (see §04)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-table-cell-max</td><td class="val" data-v-6c48fca3>700px</td><td data-v-6c48fca3>max width of a single table column; longer cell content wraps (see §04)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-bp-sm</td><td class="val" data-v-6c48fca3>640px</td><td data-v-6c48fca3>mobile / desktop boundary</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-bp-md</td><td class="val" data-v-6c48fca3>980px</td><td data-v-6c48fca3>narrow / wide screen boundary</td></tr></tbody></table><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> At ≤640px: dialogs become bottom Sheets, the sidebar collapses into an expandable drawer, and Composer toolbar controls are allowed to wrap. </div></div>',23))]),t("section",j,[a[21]||(a[21]=d(`<div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>03</span><h2 class="sec-title" data-v-6c48fca3>Primitives</h2></div><p class="sec-desc" data-v-6c48fca3> Component primitives are the "smallest correct units" of the site UI. Each primitive exposes variants along only two dimensions — <code data-v-6c48fca3>variant</code> / <code data-v-6c48fca3>size</code> — with appearance driven by tokens, so it naturally supports light / dark mode and customizable theme colors. </p><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> For every interactive primitive, the <b data-v-6c48fca3>keyboard behavior, focus, and ARIA contract are in §08 Accessibility</b>. New primitives must ship with a keyboard model — mouse-only interaction is not enough. </div></div><h3 class="sub" data-v-6c48fca3>Component selection guide</h3><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Scenario</th><th data-v-6c48fca3>Use</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td data-v-6c48fca3>Primary action (submit / confirm)</td><td data-v-6c48fca3><code data-v-6c48fca3>Button variant=primary</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Secondary action / cancel</td><td data-v-6c48fca3><code data-v-6c48fca3>Button secondary</code> / <code data-v-6c48fca3>ghost</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Destructive action (delete / abort)</td><td data-v-6c48fca3><code data-v-6c48fca3>Button danger</code> / <code data-v-6c48fca3>danger-soft</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Status marker</td><td data-v-6c48fca3><code data-v-6c48fca3>Badge</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Toolbar filter / model switch</td><td data-v-6c48fca3><code data-v-6c48fca3>Pill</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>2–4 mutually exclusive options</td><td data-v-6c48fca3><code data-v-6c48fca3>SegmentedControl</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Top tabs</td><td data-v-6c48fca3><code data-v-6c48fca3>Tabs</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Switch / multi-select</td><td data-v-6c48fca3><code data-v-6c48fca3>Switch</code> / <code data-v-6c48fca3>Checkbox</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Floating content card / list action menu</td><td data-v-6c48fca3><code data-v-6c48fca3>Card</code> / <code data-v-6c48fca3>Menu</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Inline notice / global toast</td><td data-v-6c48fca3><code data-v-6c48fca3>Banner</code> / <code data-v-6c48fca3>Toast</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Dialog / confirmation · bottom panel (mobile)</td><td data-v-6c48fca3><code data-v-6c48fca3>Dialog</code> / <code data-v-6c48fca3>Sheet</code></td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Button</h3><p data-v-6c48fca3>4 semantic variants × 3 sizes. The primary action <code data-v-6c48fca3>primary</code> takes its color from the current theme color (§05 can switch between the blue and black families). Radius uses <code data-v-6c48fca3>--radius-md</code> uniformly (small size <code data-v-6c48fca3>--radius-sm</code>), weight 600, with a visible focus ring.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Variant matrix <span class="tag spec" data-v-6c48fca3>light</span></span><span class="sactions" data-v-6c48fca3><span class="tab on" data-v-6c48fca3>preview</span></span></div><div class="stage p col" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>medium · default</span><div class="demo-row" data-v-6c48fca3><button class="p-btn primary" data-v-6c48fca3>Primary action</button><button class="p-btn secondary" data-v-6c48fca3>Secondary action</button><button class="p-btn ghost" data-v-6c48fca3>Ghost button</button><button class="p-btn danger-soft" data-v-6c48fca3>Destructive (soft)</button><button class="p-btn danger" data-v-6c48fca3>Destructive action</button></div><span class="stage-label" data-v-6c48fca3>small</span><div class="demo-row" data-v-6c48fca3><button class="p-btn primary sm" data-v-6c48fca3>Confirm</button><button class="p-btn secondary sm" data-v-6c48fca3>Cancel</button><button class="p-btn ghost sm" data-v-6c48fca3>More</button></div><span class="stage-label" data-v-6c48fca3>With icon / state</span><div class="demo-row" data-v-6c48fca3><button class="p-btn primary" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" data-v-6c48fca3></path></svg>New chat</button><button class="p-btn secondary" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg>Copied</button><button class="p-btn primary disabled" data-v-6c48fca3>Loading…</button></div></div></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Dark skin <span class="tag spec" data-v-6c48fca3>dark</span></span></div><div class="stage dark p col" data-p="dark" data-v-6c48fca3><div class="demo-row" data-v-6c48fca3><button class="p-btn primary" data-v-6c48fca3>Primary action</button><button class="p-btn secondary" data-v-6c48fca3>Secondary action</button><button class="p-btn ghost" data-v-6c48fca3>Ghost button</button><button class="p-btn danger" data-v-6c48fca3>Destructive action</button></div></div></div><h4 class="mini" data-v-6c48fca3>API</h4><div class="code" data-v-6c48fca3><div class="code-bar" data-v-6c48fca3><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="fn" data-v-6c48fca3>Button.vue · usage</span></div><pre data-v-6c48fca3><span class="k" data-v-6c48fca3><Button</span> <span class="p" data-v-6c48fca3>variant</span>=<span class="s" data-v-6c48fca3>"primary"</span> <span class="p" data-v-6c48fca3>size</span>=<span class="s" data-v-6c48fca3>"md"</span> <span class="p" data-v-6c48fca3>:loading</span>=<span class="s" data-v-6c48fca3>"submitting"</span><span class="k" data-v-6c48fca3>></span>Save<span class="k" data-v-6c48fca3></Button></span>
|
|
7
|
+
<span class="c" data-v-6c48fca3>// variant: primary | secondary | ghost | danger | danger-soft</span>
|
|
8
|
+
<span class="c" data-v-6c48fca3>// size: sm | md | lg</span></pre></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>States</span></div><div class="stage p" data-v-6c48fca3><div class="demo-row" data-v-6c48fca3><button class="p-btn primary" disabled style="opacity:.5;cursor:not-allowed;" data-v-6c48fca3>Disabled primary</button><button class="p-btn primary" data-v-6c48fca3><svg class="p-spinner sm" viewBox="0 0 24 24" data-v-6c48fca3><circle class="track" cx="12" cy="12" r="9" data-v-6c48fca3></circle><circle class="arc" cx="12" cy="12" r="9" data-v-6c48fca3></circle></svg>Submitting</button><button class="p-btn danger" disabled style="opacity:.5;cursor:not-allowed;" data-v-6c48fca3>Disabled danger</button></div></div></div><h3 class="sub" data-v-6c48fca3>IconButton</h3><p data-v-6c48fca3>Unified into three sizes — 26 / 32 / 44px — with a light-grey hover background and a visible focus ring. Replaces the ad-hoc icon + click areas scattered across components today.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>IconButton</span></div><div class="stage p" data-v-6c48fca3><button class="p-icon-btn" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" data-v-6c48fca3></path></svg></button><button class="p-icon-btn" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M3 4h18v2H3zm0 7h18v2H3zm0 7h18v2H3z" data-v-6c48fca3></path></svg></button><button class="p-icon-btn" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z" data-v-6c48fca3></path></svg></button><button class="p-icon-btn sm" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z" data-v-6c48fca3></path></svg></button><button class="p-icon-btn sm" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg></button></div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> The desktop IconButton comes in <code data-v-6c48fca3>sm</code> 26 / <code data-v-6c48fca3>md</code> 32; on touch devices the tap target should be ≥ 44px, so use <code data-v-6c48fca3>lg</code> 44px, satisfying the §01 accessibility principle (the mobile three-piece set uses <code data-v-6c48fca3>lg</code>). </div></div><h3 class="sub" data-v-6c48fca3>Badge · Chip · Pill</h3><p data-v-6c48fca3>Collapsed into two kinds: <b data-v-6c48fca3>Badge</b> (status badge, with an optional status dot) and <b data-v-6c48fca3>Pill</b> (the clickable pill in the composer toolbar). Radius, font size, and padding are all unified.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Badge · status badge</span></div><div class="stage p col" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>Semantic variants</span><div class="demo-row" data-v-6c48fca3><span class="p-badge neutral" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>pending</span><span class="p-badge info" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>running</span><span class="p-badge success" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>completed</span><span class="p-badge warning" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>needs confirmation</span><span class="p-badge danger" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>failed</span><span class="p-badge solid" data-v-6c48fca3>KIMI</span></div><span class="stage-label" data-v-6c48fca3>With icon / small size</span><div class="demo-row" data-v-6c48fca3><span class="p-badge info" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M4 3h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1m1 2v14h14V5z" data-v-6c48fca3></path></svg>plan</span><span class="p-badge success sm" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>passed</span><span class="p-badge neutral sm" data-v-6c48fca3>read-only</span></div></div></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Pill · toolbar pill (composer)</span></div><div class="stage p" data-v-6c48fca3><span class="p-pill" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M8 4h13v2H8zM4.5 6.5a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 6.9a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3M8 11h13v2H8zm0 7h13v2H8z" data-v-6c48fca3></path></svg><span class="pp-strong" data-v-6c48fca3>kimi-k2</span><span class="pp-sub" data-v-6c48fca3>· thinking</span><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12 13.171l4.95-4.95l1.414 1.415L12 16L5.636 9.636L7.05 8.222z" data-v-6c48fca3></path></svg></span><span class="p-pill" data-v-6c48fca3><span style="width:7px;height:7px;border-radius:50%;background:var(--p-warning);" data-v-6c48fca3></span>yolo</span><span class="p-pill" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16m1-8h4v2h-6V7h2z" data-v-6c48fca3></path></svg>12k / 200k</span></div></div><h3 class="sub" data-v-6c48fca3>Kbd · keyboard shortcut</h3><p data-v-6c48fca3><b data-v-6c48fca3>Kbd</b> renders a shortcut as keycaps — one block per key, never inline text like <code data-v-6c48fca3>(⌘K)</code>. Caps are 18px tall (Badge sm rhythm): sunken surface, 1px border with a 2px bottom edge, 11px UI font, muted text. Typical placement: pushed to the row's trailing edge, opposite the label (e.g. the sidebar search row).</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Kbd · keycaps</span></div><div class="stage p" data-v-6c48fca3><span class="p-kbd" data-v-6c48fca3><kbd data-v-6c48fca3>⌘</kbd><kbd data-v-6c48fca3>K</kbd></span><span class="p-kbd" data-v-6c48fca3><kbd data-v-6c48fca3>Ctrl</kbd><kbd data-v-6c48fca3>K</kbd></span><span class="p-kbd" data-v-6c48fca3><kbd data-v-6c48fca3>⌘</kbd><kbd data-v-6c48fca3>⇧</kbd><kbd data-v-6c48fca3>P</kbd></span></div></div><h3 class="sub" data-v-6c48fca3>Card / Surface</h3><p data-v-6c48fca3>All cards across the site share <b data-v-6c48fca3>one shell</b>: flat, <code data-v-6c48fca3>1px</code> border, <code data-v-6c48fca3>--radius-md</code> radius, <b data-v-6c48fca3>no shadow</b>. The structure is split into three parts — <code data-v-6c48fca3>head / body / foot</code>. Cards differ <b data-v-6c48fca3>only in the head</b> — in two tiers by visual weight, while the shell stays consistent:</p><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3><b data-v-6c48fca3>Operation card</b> —— "process" content such as tool calls, Agent, Todo. The head is compact mono with no fill, low weight by default, not competing with the conversation.</li><li data-v-6c48fca3><b data-v-6c48fca3>Attention card</b> —— content that needs a user decision, such as Question / Approval. The head carries a semantic color band (accent / warning) to stand out from the message stream.</li></ul><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Operation card · compact mono head (no fill)</span></div><div class="stage p col" data-v-6c48fca3><div class="p-card" style="max-width:460px;" data-v-6c48fca3><div class="p-card-head" data-v-6c48fca3><span class="p-card-title" data-v-6c48fca3>read_file</span><span class="p-badge info sm" style="margin-left:auto;" data-v-6c48fca3>session.ts</span></div><div class="p-card-body" data-v-6c48fca3>The head uses mono + a neutral background to emphasize its "code / process" nature; the body uses sans for readability. Flat, radius-md, same shape as the tool group and Agent group.</div></div></div></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Attention card · semantic color-band head (accent / warning)</span></div><div class="stage p col" data-v-6c48fca3><div class="p-action" style="max-width:460px;" data-v-6c48fca3><div class="p-action-head" data-v-6c48fca3><span class="p-action-title" data-v-6c48fca3>A decision needs your confirmation</span><span class="p-badge info sm" style="margin-left:auto;" data-v-6c48fca3>question</span></div><div class="p-action-body" data-v-6c48fca3>The head uses a semantic light background (<code data-v-6c48fca3>accent-soft</code> / <code data-v-6c48fca3>warning-soft</code>) to stand out from the message stream, signaling that the user must step in. The shell is exactly the same as the operation card.</div></div></div></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Group · the container owns the border, rows are separated by hairlines</span></div><div class="stage p col" data-v-6c48fca3><div class="p-tool-group open" style="max-width:460px;" data-v-6c48fca3><div class="p-tool-group-head" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tg-title" data-v-6c48fca3>3 tool calls</span><span class="tg-meta" data-v-6c48fca3>· completed</span></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>session.ts</span></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tr-name" data-v-6c48fca3>grep</span><span class="tr-arg" data-v-6c48fca3>"jwt" · 4 hits</span></div></div></div></div><ul class="clean check" data-v-6c48fca3><li data-v-6c48fca3><b data-v-6c48fca3>Unified shell</b>: all cards are flat + 1px border + radius-md, casting no shadow.</li><li data-v-6c48fca3><b data-v-6c48fca3>Differences are intentional</b>: only the head distinguishes the type (compact mono vs semantic color band); the shell stays consistent.</li><li data-v-6c48fca3><b data-v-6c48fca3>Grouping</b>: the outer container owns the border and radius; inner rows are separated by <code data-v-6c48fca3>border-top</code> hairlines, rather than each row being its own card.</li><li data-v-6c48fca3><b data-v-6c48fca3>Status dots</b>: running (pulsing blue) / done (green) / failed (red), sharing one color vocabulary (see §04 tool calls).</li></ul><h3 class="sub" data-v-6c48fca3>Input / Select / Textarea</h3><p data-v-6c48fca3>Unified 38px height (32px small), <code data-v-6c48fca3>--radius-md</code> radius, <code data-v-6c48fca3>--color-surface-raised</code> background, and a unified blue focus ring (<code data-v-6c48fca3>0 0 0 3px accent-soft</code>).</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Form primitives</span></div><div class="stage p col" data-v-6c48fca3><div class="demo-row" style="align-items:flex-start;" data-v-6c48fca3><div class="p-field demo-grow" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>Workspace name</label><input class="p-input" placeholder="e.g. frontend" data-v-6c48fca3><span class="p-hint" data-v-6c48fca3>Only letters, numbers, and hyphens are allowed.</span></div><div class="p-field demo-grow" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>Model provider</label><select class="p-select" data-v-6c48fca3><option data-v-6c48fca3>Anthropic</option><option data-v-6c48fca3>OpenAI</option><option data-v-6c48fca3>Moonshot</option></select></div></div><div class="p-field" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>System prompt</label><textarea class="p-textarea" placeholder="Describe this Agent's role and boundaries…" data-v-6c48fca3></textarea></div></div></div><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>States</span></div><div class="stage p col" data-v-6c48fca3><div class="demo-row" style="align-items:flex-start;" data-v-6c48fca3><div class="p-field demo-grow" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>Workspace name</label><input class="p-input" value="my workspace!" style="border-color:var(--p-danger);" data-v-6c48fca3><span class="p-field-error" data-v-6c48fca3>Please enter a valid workspace name</span></div><div class="p-field demo-grow" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>Display name</label><input class="p-input" value="frontend" data-v-6c48fca3><span class="p-hint" data-v-6c48fca3>Normal state · validation passed</span></div></div></div></div><h3 class="sub" data-v-6c48fca3>Code / Diff</h3><p data-v-6c48fca3>Inline code, code blocks, and diffs all use the monospace font (<code data-v-6c48fca3>--p-font-mono</code>). Code blocks have a filename title bar and a copy button. Diffs use <code data-v-6c48fca3>+</code> / <code data-v-6c48fca3>-</code> row colors to express additions and deletions — additions use a success light background, deletions use a danger light background, with no gradients.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Code / Diff</span></div><div class="stage p col" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>inline code</span><div data-v-6c48fca3>The server uses <code class="p-code-inline" data-v-6c48fca3>jwt.verify(token)</code> to verify the signature, returning 401 on failure.</div><span class="stage-label" data-v-6c48fca3>code block</span><div class="p-code-block" data-v-6c48fca3><div class="p-code-block-head" data-v-6c48fca3><span data-v-6c48fca3>session.ts</span><button class="p-icon-btn sm" aria-label="Copy" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1 1 0 0 1 3 21l.003-14c0-.552.45-1 1.006-1zM5.002 8L5 20h10V8zM9 6h8v10h2V4H9z" data-v-6c48fca3></path></svg></button></div><pre data-v-6c48fca3>import { verify } from './jwt';
|
|
9
|
+
|
|
10
|
+
export function auth(token: string) {
|
|
11
|
+
return verify(token, process.env.JWT_SECRET!);
|
|
12
|
+
}</pre></div><span class="stage-label" data-v-6c48fca3>diff</span><div class="p-diff" data-v-6c48fca3><div class="p-diff-head" data-v-6c48fca3>session.ts · +3 -1</div><div class="p-diff-row" data-v-6c48fca3><span class="pm" data-v-6c48fca3></span><span class="p-diff-code" data-v-6c48fca3>import { verify } from './jwt';</span></div><div class="p-diff-row del" data-v-6c48fca3><span class="pm" data-v-6c48fca3>-</span><span class="p-diff-code" data-v-6c48fca3>const secret = 'dev-secret';</span></div><div class="p-diff-row add" data-v-6c48fca3><span class="pm" data-v-6c48fca3>+</span><span class="p-diff-code" data-v-6c48fca3>const secret = process.env.JWT_SECRET!;</span></div><div class="p-diff-row" data-v-6c48fca3><span class="pm" data-v-6c48fca3></span><span class="p-diff-code" data-v-6c48fca3>return verify(token, secret);</span></div></div></div></div><h3 class="sub" data-v-6c48fca3>Dialog</h3><p data-v-6c48fca3>One dialog primitive replaces 6 hand-written implementations: unified <code data-v-6c48fca3>--radius-xl</code> radius, <code data-v-6c48fca3>--shadow-xl</code> shadow, 20px head padding, right-aligned footer actions, and an IconButton close button.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Dialog primitive</span></div><div class="stage p col" style="align-items:center;" data-v-6c48fca3><div class="p-dialog" data-v-6c48fca3><div class="p-dialog-head" data-v-6c48fca3><div data-v-6c48fca3><div class="p-dialog-title" data-v-6c48fca3>New chat</div><div class="p-dialog-desc" data-v-6c48fca3>Create an independent Agent chat in the current workspace.</div></div><button class="p-icon-btn sm" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z" data-v-6c48fca3></path></svg></button></div><div class="p-dialog-body" data-v-6c48fca3><div class="p-field" data-v-6c48fca3><label class="p-label" data-v-6c48fca3>Chat title (optional)</label><input class="p-input" placeholder="Generated automatically" data-v-6c48fca3></div></div><div class="p-dialog-foot" data-v-6c48fca3><button class="p-btn secondary" data-v-6c48fca3>Cancel</button><button class="p-btn primary" data-v-6c48fca3>Create</button></div></div></div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>Size & height</b>: Dialog offers three widths — <code data-v-6c48fca3>md</code> 440 / <code data-v-6c48fca3>lg</code> 640 / <code data-v-6c48fca3>xl</code> 760 (<code data-v-6c48fca3>--p-content-max</code>) — chosen by content weight. Height comes in two kinds: <code data-v-6c48fca3>auto</code> (default, grows with content up to <code data-v-6c48fca3>max-height</code>) and <code data-v-6c48fca3>fixed</code> (constant height <code data-v-6c48fca3>min(680px, 100vh - 64px)</code>, with overflow scrolled inside the body). <b data-v-6c48fca3>Content / multi-tab dialogs</b> (settings, model picker, provider manager, folder browser) always use <code data-v-6c48fca3>fixed</code> so the frame size stays constant and doesn't jump when switching tabs or content length; short confirmation dialogs keep <code data-v-6c48fca3>auto</code>. </div></div><h3 class="sub" data-v-6c48fca3>Toast</h3><p data-v-6c48fca3>Unified information architecture: status icon + title + description. The status color appears only on the icon, avoiding large colored areas that create visual noise.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Toast</span></div><div class="stage p col" data-v-6c48fca3><div class="p-toast success" data-v-6c48fca3><span class="ti" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg></span><div data-v-6c48fca3><div class="tt" data-v-6c48fca3>Connected to server</div><div class="td" data-v-6c48fca3>The local daemon is responding normally; you can start a new chat.</div></div></div><div class="p-toast warning" data-v-6c48fca3><span class="ti" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12.866 3l9.526 16.5a1 1 0 0 1-.866 1.5H2.474a1 1 0 0 1-.866-1.5L11.134 3a1 1 0 0 1 1.732 0m-8.66 16h15.588L12 5.5zM11 16h2v2h-2zm0-7h2v5h-2z" data-v-6c48fca3></path></svg></span><div data-v-6c48fca3><div class="tt" data-v-6c48fca3>Context usage 82%</div><div class="td" data-v-6c48fca3>Consider running /compact to free up space.</div></div></div></div></div><h3 class="sub" data-v-6c48fca3>Spinner</h3><p data-v-6c48fca3>Loaders fall into two categories by scenario — <b data-v-6c48fca3>do not mix them</b>:</p><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3><b data-v-6c48fca3>Spinner (plain · SVG ring)</b> —— the default loader. Used for button loading, app startup (GlobalLoading), and general inline waits — "everything else".</li><li data-v-6c48fca3><b data-v-6c48fca3>MoonSpinner (moon phase · brand signature)</b> —— used <b data-v-6c48fca3>only</b> for the chat waiting state of "message sent, waiting for the Agent's first response" (the sending placeholder in ChatPane, SideChatPanel, ActivityNotice).</li></ul><h4 class="mini" data-v-6c48fca3>Spinner · plain loader (default)</h4>`,48)),t("div",E,[a[14]||(a[14]=t("div",{class:"stage-bar"},[t("span",{class:"st"},"Spinner · common scenarios")],-1)),t("div",F,[t("div",_,[a[13]||(a[13]=d('<svg class="p-spinner" viewBox="0 0 24 24" data-v-6c48fca3><circle class="track" cx="12" cy="12" r="9" data-v-6c48fca3></circle><circle class="arc" cx="12" cy="12" r="9" data-v-6c48fca3></circle></svg><span class="p-thinking" data-v-6c48fca3><svg class="p-spinner sm" viewBox="0 0 24 24" data-v-6c48fca3><circle class="track" cx="12" cy="12" r="9" data-v-6c48fca3></circle><circle class="arc" cx="12" cy="12" r="9" data-v-6c48fca3></circle></svg>Loading…</span>',2)),t("button",K,[(c(),s("svg",G,[...a[11]||(a[11]=[t("circle",{class:"track",cx:"12",cy:"12",r:"9"},null,-1),t("circle",{class:"arc",cx:"12",cy:"12",r:"9"},null,-1)])])),a[12]||(a[12]=o("Submitting",-1))])])])]),a[22]||(a[22]=d('<h4 class="mini" data-v-6c48fca3>MoonSpinner · moon phase (only "waiting for the Agent")</h4><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>MoonSpinner · chat waiting state only <span class="tag spec" data-v-6c48fca3>signature</span></span></div><div class="stage p col" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>Frame loop (8 frames)</span><div class="demo-row" style="font-size:22px;letter-spacing:2px;line-height:1;" data-v-6c48fca3><span data-v-6c48fca3>🌑</span><span data-v-6c48fca3>🌒</span><span data-v-6c48fca3>🌓</span><span data-v-6c48fca3>🌔</span><span data-v-6c48fca3>🌕</span><span data-v-6c48fca3>🌖</span><span data-v-6c48fca3>🌗</span><span data-v-6c48fca3>🌘</span></div><span class="stage-label" data-v-6c48fca3>Usage · only while the chat waits for a response</span><div class="demo-row" data-v-6c48fca3><span class="p-thinking" data-v-6c48fca3><span style="font-size:16px;line-height:1;" data-v-6c48fca3>🌔</span>Thinking…</span><span class="p-thinking" data-v-6c48fca3><span style="font-size:16px;line-height:1;" data-v-6c48fca3>🌕</span>Waiting for response…</span></div></div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3>The moon phase is the <b data-v-6c48fca3>sole exception</b> to the emoji-as-icon rule, and is <b data-v-6c48fca3>limited</b> to the "waiting for the Agent's first response" scenario. It is currently implemented twice — in <code data-v-6c48fca3>MoonSpinner.vue</code> and <code data-v-6c48fca3>ActivityNotice.vue</code> — and should be merged into a single <code data-v-6c48fca3>MoonSpinner</code> component, sized via tokens and supporting <code data-v-6c48fca3>prefers-reduced-motion</code>. All other loading states use the plain Spinner.</div></div><h3 class="sub" data-v-6c48fca3>Link</h3><p data-v-6c48fca3>Inline text link: the default is the accent color with no underline; on hover it shows an underline and darkens. The <code data-v-6c48fca3>.muted</code> variant uses the secondary text color. Used for in-text jumps, external links, "view all", and other lightweight actions.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Link · inline link</span></div><div class="stage p col" data-v-6c48fca3><div class="demo-row" style="font-size:var(--p-font-size-base);color:var(--p-text);" data-v-6c48fca3><span data-v-6c48fca3>Read the full <a class="p-link" href="#" data-v-6c48fca3>design token docs</a> before building.</span><a class="p-link" href="#" data-v-6c48fca3>View on GitHub<svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M10 6v2H5v11h11v-5h2v6a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm11-3v8h-2V6.413l-7.793 7.794l-1.414-1.414L17.585 5H13V3z" data-v-6c48fca3></path></svg></a><a class="p-link muted" href="#" data-v-6c48fca3>View history</a></div></div></div><h3 class="sub" data-v-6c48fca3>Menu / Dropdown</h3><p data-v-6c48fca3>Dropdown menu panel: raised surface + border + light shadow (<code data-v-6c48fca3>--shadow-sm</code>, flat-leaning). Menu items support icons, the current (active) state, the danger state, and the disabled state, with separators grouping items. On touch / mobile, use <code data-v-6c48fca3>lg</code> (≥44px row height) for menu items.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Menu · dropdown menu</span></div><div class="stage p col" style="align-items:flex-start;" data-v-6c48fca3><div class="p-menu" data-v-6c48fca3><div class="p-menu-item" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8zM5.83 8H9V4.83zM11 4v5a1 1 0 0 1-1 1H5v10h14V4z" data-v-6c48fca3></path></svg>Open file</div><div class="p-menu-item active" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg>Selected item</div><div class="p-menu-item disabled" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16M8.523 7.109l8.368 8.368a6 6 0 0 1-1.414 1.414L7.109 8.523A6 6 0 0 1 8.523 7.11" data-v-6c48fca3></path></svg>Disabled item</div><div class="p-menu-sep" data-v-6c48fca3></div><div class="p-menu-item danger" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z" data-v-6c48fca3></path></svg>Delete chat</div></div></div></div><h3 class="sub" data-v-6c48fca3>SegmentedControl</h3><p data-v-6c48fca3>Mutually exclusive short option groups, commonly used for 2–4 option switches such as "light / dark / follow system". The current item is highlighted with a raised surface + subtle shadow.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>SegmentedControl</span></div><div class="stage p col" data-v-6c48fca3><div class="p-seg" data-v-6c48fca3><span class="p-seg-item on" data-v-6c48fca3>Light</span><span class="p-seg-item" data-v-6c48fca3>Dark</span><span class="p-seg-item" data-v-6c48fca3>Follow system</span></div></div></div><h3 class="sub" data-v-6c48fca3>Tabs</h3><p data-v-6c48fca3>Tabs with a bottom hairline, used for grouping and switching sibling content. The current tab is marked with accent text + an accent underline.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Tabs</span></div><div class="stage p col" data-v-6c48fca3><div class="p-tabs" data-v-6c48fca3><span class="p-tab on" data-v-6c48fca3>General</span><span class="p-tab" data-v-6c48fca3>Agent</span><span class="p-tab" data-v-6c48fca3>Advanced</span></div></div></div><h3 class="sub" data-v-6c48fca3>Switch</h3><p data-v-6c48fca3>A two-state switch for settings that take effect immediately. 36×20 track with full radius, 16px knob; when on, the track turns accent and the knob slides right, with the transition driven by tokens.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Switch</span></div><div class="stage p" data-v-6c48fca3><span class="p-switch on" data-v-6c48fca3></span><span class="p-switch" data-v-6c48fca3></span></div></div><h3 class="sub" data-v-6c48fca3>Checkbox</h3><p data-v-6c48fca3>A 17×17 checkbox. When checked it fills with the accent color and shows a white tick (inline SVG). Often paired with a text label.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Checkbox</span></div><div class="stage p" data-v-6c48fca3><span class="p-check on" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg></span><span class="p-check" data-v-6c48fca3></span><label style="display:inline-flex;align-items:center;gap:8px;color:var(--p-text);font-size:var(--p-font-size-base);cursor:pointer;" data-v-6c48fca3><span class="p-check on" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m10 15.17l9.192-9.191l1.414 1.414L10 17.999l-6.364-6.364l1.414-1.414z" data-v-6c48fca3></path></svg></span>Enable auto-save</label></div></div><h3 class="sub" data-v-6c48fca3>Avatar</h3><p data-v-6c48fca3>A 32px default avatar with md radius; <code data-v-6c48fca3>.sm</code> is 24px. Can hold an initial or an icon; falls back to this placeholder when there is no image.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Avatar</span></div><div class="stage p" data-v-6c48fca3><span class="p-avatar" data-v-6c48fca3>K</span><span class="p-avatar" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M4 22a8 8 0 1 1 16 0h-2a6 6 0 0 0-12 0zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6s6 2.685 6 6s-2.685 6-6 6m0-2c2.21 0 4-1.79 4-4s-1.79-4-4-4s-4 1.79-4 4s1.79 4 4 4" data-v-6c48fca3></path></svg></span><span class="p-avatar sm" data-v-6c48fca3>K</span></div></div><h3 class="sub" data-v-6c48fca3>EmptyState</h3><p data-v-6c48fca3>A centered placeholder for empty lists / panels: a 48px faint icon + title + hint, avoiding blank pages.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>EmptyState</span></div><div class="stage p col" data-v-6c48fca3><div class="p-empty" style="width:100%;border:1px dashed var(--p-line);border-radius:var(--p-r-lg);" data-v-6c48fca3><svg class="em-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M6.455 19L2 22.5V4a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1zm-.692-2H20V5H4v13.385zM8 10h8v2H8z" data-v-6c48fca3></path></svg><div class="em-title" data-v-6c48fca3>No chats yet</div><div class="em-hint" data-v-6c48fca3>Click "New chat" to start a conversation with Dimi</div></div></div></div><h3 class="sub" data-v-6c48fca3>Divider</h3><p data-v-6c48fca3>A 1px horizontal divider (<code data-v-6c48fca3>--p-line</code>); <code data-v-6c48fca3>.p-divider-v</code> is the vertical divider, used between inline elements.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Divider</span></div><div class="stage p col" data-v-6c48fca3><div style="width:100%;font-size:var(--p-font-size-sm);color:var(--p-text);" data-v-6c48fca3>Content above</div><hr class="p-divider" data-v-6c48fca3><div style="width:100%;font-size:var(--p-font-size-sm);color:var(--p-text);" data-v-6c48fca3>Content below</div><div style="display:flex;align-items:center;gap:10px;height:24px;font-size:var(--p-font-size-sm);color:var(--p-text);" data-v-6c48fca3><span data-v-6c48fca3>kimi-k2</span><span class="p-divider-v" data-v-6c48fca3></span><span data-v-6c48fca3>thinking</span></div></div></div><h3 class="sub" data-v-6c48fca3>Tooltip</h3><p data-v-6c48fca3>A CSS-only hover hint, wrapped in <code data-v-6c48fca3>.p-tip</code>. Inverted background (<code data-v-6c48fca3>--p-text</code> / <code data-v-6c48fca3>--p-bg</code>), single line, no wrapping — carries only short notes.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Tooltip (hover the button)</span></div><div class="stage p" data-v-6c48fca3><span class="p-tip" data-v-6c48fca3><button class="p-icon-btn" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" data-v-6c48fca3></path></svg></button><span class="p-tooltip" data-v-6c48fca3>New chat</span></span></div></div><h3 class="sub" data-v-6c48fca3>Banner</h3><p data-v-6c48fca3>An inline notice bar placed at the top of a content area. Three states — <code data-v-6c48fca3>.info</code> / <code data-v-6c48fca3>.warning</code> / <code data-v-6c48fca3>.danger</code> — each with a matching 18px icon.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Banner</span></div><div class="stage p col" data-v-6c48fca3><div class="p-banner info" data-v-6c48fca3><svg class="bn-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16M11 7h2v2h-2zm0 4h2v6h-2z" data-v-6c48fca3></path></svg>Connected to server</div><div class="p-banner warning" data-v-6c48fca3><svg class="bn-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12.866 3l9.526 16.5a1 1 0 0 1-.866 1.5H2.474a1 1 0 0 1-.866-1.5L11.134 3a1 1 0 0 1 1.732 0m-8.66 16h15.588L12 5.5zM11 16h2v2h-2zm0-7h2v5h-2z" data-v-6c48fca3></path></svg>Currently in yolo mode; tool calls will run automatically</div></div></div><h3 class="sub" data-v-6c48fca3>Sheet / BottomSheet</h3><p data-v-6c48fca3>A mobile bottom slide-up panel: xl top radius + drag handle, xl shadow. At ≤640px, dialogs become bottom-anchored Sheets.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>BottomSheet</span></div><div class="stage p col" style="align-items:center;" data-v-6c48fca3><div class="p-sheet" style="width:100%;max-width:360px;" data-v-6c48fca3><div class="p-sheet-handle" data-v-6c48fca3></div><div style="font-size:var(--p-font-size-base);font-weight:700;color:var(--p-text);margin-bottom:8px;" data-v-6c48fca3>Choose a model</div><div class="p-menu-item" style="padding:8px 10px;" data-v-6c48fca3>kimi-k2 · thinking</div><div class="p-menu-item" style="padding:8px 10px;" data-v-6c48fca3>kimi-k2 · instant</div></div></div></div><h3 class="sub" data-v-6c48fca3>Skeleton</h3><p data-v-6c48fca3>A placeholder for loading content, using a breathing opacity animation (no gradients), following the <code data-v-6c48fca3>no-gradient-text</code> rule. Composed into titles / text lines / avatars.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Skeleton</span></div><div class="stage p col" data-v-6c48fca3><div style="display:flex;flex-direction:column;gap:10px;width:100%;max-width:360px;" data-v-6c48fca3><div class="p-skeleton" style="height:16px;width:55%;" data-v-6c48fca3></div><div class="p-skeleton" style="height:12px;width:100%;" data-v-6c48fca3></div><div class="p-skeleton" style="height:12px;width:82%;" data-v-6c48fca3></div><div class="p-skeleton" style="height:32px;width:32px;border-radius:var(--p-r-full);" data-v-6c48fca3></div></div></div></div><h3 class="sub" data-v-6c48fca3>Command Bar</h3><p data-v-6c48fca3>An inline combination of "primary action + command text + copy", sitting between a button and a code block — used for install / onboarding / one-click execution. The primary action reuses <code data-v-6c48fca3>Button primary</code>; the command area uses a mono light-grey background.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Command Bar</span></div><div class="stage p col" data-v-6c48fca3><div class="p-cmdbar" style="max-width:620px;" data-v-6c48fca3><button class="p-btn primary" data-v-6c48fca3>Install Dimi ▾</button><span class="p-cmd" data-v-6c48fca3><span class="cmd-text" data-v-6c48fca3>curl -fsSL https://github.com/zzj3720/dimi/releases/latest/download/install.sh | bash</span><button class="cmd-copy" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1 1 0 0 1 3 21l.003-14c0-.552.45-1 1.006-1zM5.002 8L5 20h10V8zM9 6h8v10h2V4H9z" data-v-6c48fca3></path></svg></button></span></div></div></div><h3 class="sub" data-v-6c48fca3>TopBar</h3><p data-v-6c48fca3>The application top bar. Solid by default; the <code data-v-6c48fca3>.frost</code> variant is translucent + background blur, used <b data-v-6c48fca3>only for sticky navigation bars</b>, and is the sole exception to the <code data-v-6c48fca3>no-glassmorphism</code> rule (see §06).</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>TopBar · solid / frosted glass</span></div><div class="stage p col" style="gap:14px;background:radial-gradient(circle at 18% 30%,rgba(23,131,255,.16),transparent 42%),radial-gradient(circle at 82% 75%,rgba(20,23,28,.10),transparent 46%),var(--p-surface-sunken);" data-v-6c48fca3><div class="p-topbar" style="width:100%;max-width:580px;" data-v-6c48fca3><span class="tb-title" data-v-6c48fca3>Solid TopBar</span><span class="tb-actions" data-v-6c48fca3><button class="p-icon-btn sm" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M3 4h18v2H3zm0 7h18v2H3zm0 7h18v2H3z" data-v-6c48fca3></path></svg></button></span></div><div class="p-topbar frost" style="width:100%;max-width:580px;" data-v-6c48fca3><span class="tb-title" data-v-6c48fca3>Frosted-glass TopBar · .frost</span><span class="tb-actions" data-v-6c48fca3><button class="p-icon-btn sm" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M3 4h18v2H3zm0 7h18v2H3zm0 7h18v2H3z" data-v-6c48fca3></path></svg></button></span></div></div></div><h3 class="sub" data-v-6c48fca3>SectionLabel</h3><p data-v-6c48fca3>A small group title for sidebar lists, used to section the content below (such as <code data-v-6c48fca3>Workspaces</code> in the sidebar). Spec: 13px / 700 / uppercase / letter-spacing <code data-v-6c48fca3>.08em</code>, color <code data-v-6c48fca3>--color-fg-faint</code>; left-aligned to the row's starting padding (<code data-v-6c48fca3>--sb-pad-x</code>), keeping the same indent as the group rows below. For scripts without case (such as Chinese), <code data-v-6c48fca3>text-transform:uppercase</code> simply has no effect — no special handling needed.</p>',50)),t("div",J,[a[20]||(a[20]=t("div",{class:"stage-bar"},[t("span",{class:"st"},"Sidebar · group title")],-1)),t("div",Q,[a[19]||(a[19]=t("div",{class:"p-section-label",style:{padding:"12px 16px 4px"}},"Workspaces",-1)),t("div",Y,[(c(),s("svg",X,[...a[15]||(a[15]=[t("path",{fill:"currentColor",d:"M4 5v14h16V7h-8.414l-2-2zm8.414 0H21a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414z"},null,-1)])])),a[16]||(a[16]=o(" dimi-web ",-1))]),t("div",Z,[(c(),s("svg",$,[...a[17]||(a[17]=[t("path",{fill:"currentColor",d:"M4 5v14h16V7h-8.414l-2-2zm8.414 0H21a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h7.414z"},null,-1)])])),a[18]||(a[18]=o(" playground ",-1))])])])]),t("section",aa,[a[34]||(a[34]=d('<div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>04</span><h2 class="sec-title" data-v-6c48fca3>Chat Interface Overhaul</h2></div><p class="sec-desc" data-v-6c48fca3> The message stream is the core of Dimi Web. The goal of the overhaul: have the 6 card types (Agent / Tool / Question / Approval / Swarm / Todo) <b data-v-6c48fca3>share one card skeleton</b>, distinguished only by the head icon and semantic color; and collapse the Composer into a single rounded container. </p><h3 class="sub" data-v-6c48fca3>Unified message stream</h3>',3)),t("div",ta,[a[33]||(a[33]=t("div",{class:"stage-bar"},[t("span",{class:"st"},"Conversation · 760px reading column")],-1)),t("div",ca,[t("div",sa,[a[31]||(a[31]=d('<div class="p-bubble-user" data-v-6c48fca3>Please change the login endpoint to JWT and add the corresponding unit tests.</div><span class="p-thinking" data-v-6c48fca3><span style="font-size:15px;line-height:1;" data-v-6c48fca3>🌔</span>Analyzing the auth module…</span><div class="p-tool-group open" data-v-6c48fca3><div class="p-tool-group-head" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M8 4h13v2H8zM4.5 6.5a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 6.9a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3M8 11h13v2H8zm0 7h13v2H8z" data-v-6c48fca3></path></svg><span class="tg-title" data-v-6c48fca3>3 tool calls</span><span class="tg-meta" data-v-6c48fca3>· completed · 0.8s</span><svg class="tg-car" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z" data-v-6c48fca3></path></svg></div><div class="p-tool-row expanded" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="tr-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8zM5.83 8H9V4.83zM11 4v5a1 1 0 0 1-1 1H5v10h14V4z" data-v-6c48fca3></path></svg><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>src/auth/session.ts</span><span class="tr-time" data-v-6c48fca3>0.2s</span><svg class="tr-car" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z" data-v-6c48fca3></path></svg></div><div class="p-tool-detail" data-v-6c48fca3><div class="p-code" data-v-6c48fca3>12 export function verify(token: string) {<br data-v-6c48fca3>13 return jwt.verify(token, getSecret());<br data-v-6c48fca3>14 }</div></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="tr-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8zM5.83 8H9V4.83zM11 4v5a1 1 0 0 1-1 1H5v10h14V4z" data-v-6c48fca3></path></svg><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>src/auth/middleware.ts</span><span class="tr-time" data-v-6c48fca3>0.2s</span><svg class="tr-car" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z" data-v-6c48fca3></path></svg></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="tr-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z" data-v-6c48fca3></path></svg><span class="tr-name" data-v-6c48fca3>grep</span><span class="tr-arg" data-v-6c48fca3>"jwt.verify" · 4 matches</span><span class="tr-time" data-v-6c48fca3>0.1s</span><svg class="tr-car" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z" data-v-6c48fca3></path></svg></div></div><div class="p-msg" data-v-6c48fca3><p data-v-6c48fca3>I looked at the structure of <code data-v-6c48fca3>src/auth</code>; it is currently based on a session cookie. The scope of the change is below — once you confirm, I'll start.</p></div>',4)),t("div",da,[t("div",ea,[(c(),s("svg",oa,[...a[23]||(a[23]=[t("path",{fill:"currentColor",d:"M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16m-1-5h2v2h-2zm2-1.645V14h-2v-1.5a1 1 0 0 1 1-1a1.5 1.5 0 1 0-1.471-1.794l-1.962-.393A3.501 3.501 0 1 1 13 13.355"},null,-1)])])),a[24]||(a[24]=t("span",{class:"p-action-title"},"A decision needs your confirmation",-1))]),a[25]||(a[25]=t("div",{class:"p-action-body"},"How long should the JWT expiry be? Default 7 days, refresh token 30 days.",-1)),a[26]||(a[26]=t("div",{class:"p-action-foot"},[t("button",{class:"p-btn secondary sm"},"Customize"),t("button",{class:"p-btn primary sm"},"Use default")],-1))]),t("div",ia,[t("div",la,[(c(),s("svg",na,[...a[27]||(a[27]=[t("path",{fill:"currentColor",d:"m12.866 3l9.526 16.5a1 1 0 0 1-.866 1.5H2.474a1 1 0 0 1-.866-1.5L11.134 3a1 1 0 0 1 1.732 0m-8.66 16h15.588L12 5.5zM11 16h2v2h-2zm0-7h2v5h-2z"},null,-1)])])),a[28]||(a[28]=t("span",{class:"p-action-title"},"Write permission required",-1)),a[29]||(a[29]=t("span",{class:"p-badge warning sm",style:{"margin-left":"auto"}},"write_file",-1))]),a[30]||(a[30]=d('<div class="p-action-body" data-v-6c48fca3>About to modify <code data-v-6c48fca3>src/auth/middleware.ts</code>, 42 lines changed. Allow?</div><div class="p-action-foot" data-v-6c48fca3><button class="p-btn secondary sm" data-v-6c48fca3>Deny</button><button class="p-btn primary sm" data-v-6c48fca3>Allow this time</button><button class="p-btn ghost sm" data-v-6c48fca3>Always allow</button></div>',2))]),a[32]||(a[32]=d('<div class="p-todo" data-v-6c48fca3><div class="p-todo-row done" data-v-6c48fca3><span class="p-todo-check" data-v-6c48fca3>✓</span>Replace session with JWT signing</div><div class="p-todo-row active" data-v-6c48fca3><span class="p-todo-check" data-v-6c48fca3>●</span>Refactor the auth middleware</div><div class="p-todo-row" data-v-6c48fca3><span class="p-todo-check" data-v-6c48fca3>○</span>Add unit tests</div></div>',1))])])]),a[35]||(a[35]=d('<p data-v-6c48fca3><b data-v-6c48fca3>Wide markdown tables (desktop):</b> regular chat prose stays within the 760px reading column (<code data-v-6c48fca3>--p-content-max</code>). On desktop a wide table may grow naturally with its content up to 1040px (<code data-v-6c48fca3>--p-table-max</code>), centred within the conversation pane; beyond that the excess scrolls horizontally inside the table's own wrapper — the page and the chat area never scroll sideways. A single column is capped at 700px (<code data-v-6c48fca3>--p-table-cell-max</code>), so long cell content wraps inside the cell instead of stretching the table. The conversation outline (TOC) keeps its usual position just outside the reading column; when a table grows past it and scrolls under the rail, the TOC is hidden temporarily and returns as soon as the table leaves, without touching the user's TOC setting. On mobile a table never breaks out of the reading column.</p><h3 class="sub" data-v-6c48fca3>Tool calls: compact by default, grouped, expand on demand</h3><p data-v-6c48fca3>High-frequency calls like <code data-v-6c48fca3>read_file</code> / <code data-v-6c48fca3>bash</code> / <code data-v-6c48fca3>grep</code> are "operational noise" — if each one took a full card, parallel triggers would quickly drown out the conversation. The new strategy splits tool calls into three tiers by <b data-v-6c48fca3>visual weight</b>, pushing them as light as possible:</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Three visual-weight tiers</span></div><div class="stage p col" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>① Tool row · lightest (default)</span><div class="p-tool-row" style="border:1px solid var(--p-line);border-radius:8px;" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="tr-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M9 2.003V2h10.998C20.55 2 21 2.455 21 2.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 20.993V8zM5.83 8H9V4.83zM11 4v5a1 1 0 0 1-1 1H5v10h14V4z" data-v-6c48fca3></path></svg><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>src/auth/session.ts</span><span class="tr-time" data-v-6c48fca3>0.2s</span></div><span class="stage-label" data-v-6c48fca3>② Tool group · medium (consecutive / parallel auto-merged; collapsed to one line)</span><div class="p-tool-group" data-v-6c48fca3><div class="p-tool-group-head" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M8 4h13v2H8zM4.5 6.5a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 6.9a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3M8 11h13v2H8zm0 7h13v2H8z" data-v-6c48fca3></path></svg><span class="tg-title" data-v-6c48fca3>3 tool calls</span><span class="tg-meta" data-v-6c48fca3>· completed · 0.8s</span><svg class="tg-car" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z" data-v-6c48fca3></path></svg></div></div><span class="stage-label" data-v-6c48fca3>③ Decision card · heavy (only question / approval, needs user input)</span><div class="p-action warn" data-v-6c48fca3><div class="p-action-head" data-v-6c48fca3><span class="p-action-title" data-v-6c48fca3>Write permission required</span><span class="p-badge warning sm" style="margin-left:auto;" data-v-6c48fca3>write_file</span></div><div class="p-action-body" style="padding:10px 14px;font-size:13px;" data-v-6c48fca3>About to modify <code data-v-6c48fca3>src/auth/middleware.ts</code>, 42 lines changed.</div></div></div></div><ul class="clean check" data-v-6c48fca3><li data-v-6c48fca3>Tool calls <b data-v-6c48fca3>render as compact rows by default</b> (30px single-line mono + status dot + key argument); no head / body / shadow.</li><li data-v-6c48fca3>Consecutive or parallel calls <b data-v-6c48fca3>auto-merge into one tool group</b>; when collapsed, the whole group takes one line (<code data-v-6c48fca3>N tool calls · status</code>).</li><li data-v-6c48fca3>Clicking a row <b data-v-6c48fca3>expands it in place</b> to show details (code / output); click again to collapse — details don't grab attention by default.</li><li data-v-6c48fca3>Status is expressed with a <b data-v-6c48fca3>colored dot</b>: running (pulsing blue) / done (green) / failed (red), taking no extra space.</li><li data-v-6c48fca3><b data-v-6c48fca3>Only two types keep a full card</b>: <code data-v-6c48fca3>Question</code> (needs an answer) and <code data-v-6c48fca3>Approval</code> (needs authorization) — they genuinely need the user's attention.</li></ul><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Tool Call · compact row (expand on demand)</span></div><div class="stage p" data-v-6c48fca3><div class="p-tool-group open" data-v-6c48fca3><div class="p-tool-group-head" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tg-title" data-v-6c48fca3>3 tool calls</span><span class="tg-meta" data-v-6c48fca3>· completed</span></div><div class="p-tool-row expanded" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>session.ts</span></div><div class="p-tool-detail" data-v-6c48fca3><div class="p-code" style="font-size:11px;padding:7px 9px;margin-top:8px;" data-v-6c48fca3>12 export function verify(…</div></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tr-name" data-v-6c48fca3>read_file</span><span class="tr-arg" data-v-6c48fca3>middleware.ts</span></div><div class="p-tool-row" data-v-6c48fca3><span class="p-dot done" data-v-6c48fca3></span><span class="tr-name" data-v-6c48fca3>grep</span><span class="tr-arg" data-v-6c48fca3>"jwt" · 4 hits</span></div></div></div></div><h3 class="sub" data-v-6c48fca3>Composer</h3><p data-v-6c48fca3>Unified into a single rounded container: <code data-v-6c48fca3>--radius-xl</code>, with the whole border turning blue + a soft focus ring on focus. Toolbar controls all use the Pill / IconButton primitives, and the send button is a 32px circle.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Composer</span></div><div class="stage p col" style="align-items:center;background:#fff;" data-v-6c48fca3><div class="p-composer" style="width:100%;max-width:620px;" data-v-6c48fca3><div class="p-composer-ta ph" data-v-6c48fca3>Message Dimi, / to run a command, @ to reference a file…</div><div class="p-composer-bar" data-v-6c48fca3><div class="p-composer-left" data-v-6c48fca3><button class="p-icon-btn" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z" data-v-6c48fca3></path></svg></button><span class="p-pill" data-v-6c48fca3><span style="width:7px;height:7px;border-radius:50%;background:var(--p-warning);" data-v-6c48fca3></span>yolo</span><span class="p-pill" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M8 4h13v2H8zM4.5 6.5a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3m0 6.9a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3M8 11h13v2H8zm0 7h13v2H8z" data-v-6c48fca3></path></svg>plan</span></div><div class="p-composer-right" data-v-6c48fca3><span class="p-pill" data-v-6c48fca3><span class="pp-strong" data-v-6c48fca3>kimi-k2</span><span class="pp-sub" data-v-6c48fca3>· thinking</span><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="m12 13.171l4.95-4.95l1.414 1.415L12 16L5.636 9.636L7.05 8.222z" data-v-6c48fca3></path></svg></span><button class="p-send" data-v-6c48fca3><svg class="p-ic" viewBox="0 0 24 24" fill="currentColor" data-v-6c48fca3><path fill="currentColor" d="M13 7.828V20h-2V7.828l-5.364 5.364l-1.414-1.414L12 4l7.778 7.778l-1.414 1.414z" data-v-6c48fca3></path></svg></button></div></div></div></div></div><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>Site-wide consistency</b>: the composer has only one radius (<code data-v-6c48fca3>--radius-xl</code> · 16px) and one height; toolbar controls all use the Pill / IconButton primitives, and the send button is a 32px circle — it no longer drifts with the theme. </div></div><h3 class="sub" data-v-6c48fca3>Responsive</h3><p data-v-6c48fca3>See §02 <code data-v-6c48fca3>--p-bp-sm</code> for the breakpoint. This section only gives mobile-adaptation pointers for the chat interface; a full mobile mockup is out of scope for this spec.</p><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> At ≤640px: dialogs anchor to the bottom as Sheets (xl top radius, top drag handle), the sidebar collapses into an expandable drawer, the Composer toolbar is allowed to wrap, and the chat reading column drops its max-width to fill the screen. </div></div>',13))]),a[37]||(a[37]=d(`<section id="themes" data-v-6c48fca3><div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>05</span><h2 class="sec-title" data-v-6c48fca3>Theming</h2></div><p class="sec-desc" data-v-6c48fca3> Dimi Web uses <b data-v-6c48fca3>one unified theme</b>: the same components, fonts, radii, shadows, and surfaces — "reskinning" only changes colors. Colors are collapsed into <b data-v-6c48fca3>4 seed tokens</b> — two theme colors + one light surface + one dark surface; the neutrals and accent are derived from them, and the semantic status colors (success / warning / danger) ship as independent palettes paired with the seeds, one set each for light / dark. </p><h3 class="sub" data-v-6c48fca3>Color seeds</h3><p data-v-6c48fca3>Day-to-day customization only needs these 4 seeds; the whole site's neutrals and accent change with them:</p><div class="panel panel-pad" style="margin:16px 0;" data-v-6c48fca3><div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;" data-v-6c48fca3><div style="text-align:center;" data-v-6c48fca3><div style="width:48px;height:48px;border-radius:12px;background:#1783ff;margin:0 auto 8px;box-shadow:var(--d-shadow-sm);" data-v-6c48fca3></div><div style="font-size:13px;font-weight:700;" data-v-6c48fca3>Theme color · primary</div><div class="mono" style="font-size:11.5px;color:var(--d-fg-muted);" data-v-6c48fca3>--accent-primary</div></div><div style="text-align:center;" data-v-6c48fca3><div style="width:48px;height:48px;border-radius:12px;background:#6b7280;margin:0 auto 8px;box-shadow:var(--d-shadow-sm);" data-v-6c48fca3></div><div style="font-size:13px;font-weight:700;" data-v-6c48fca3>Theme color · secondary</div><div class="mono" style="font-size:11.5px;color:var(--d-fg-muted);" data-v-6c48fca3>--accent-secondary</div></div><div style="text-align:center;" data-v-6c48fca3><div style="width:48px;height:48px;border-radius:12px;background:#ffffff;border:1px solid var(--d-line);margin:0 auto 8px;box-shadow:var(--d-shadow-sm);" data-v-6c48fca3></div><div style="font-size:13px;font-weight:700;" data-v-6c48fca3>Light surface</div><div class="mono" style="font-size:11.5px;color:var(--d-fg-muted);" data-v-6c48fca3>--surface-light</div></div><div style="text-align:center;" data-v-6c48fca3><div style="width:48px;height:48px;border-radius:12px;background:#0d1117;margin:0 auto 8px;box-shadow:var(--d-shadow-sm);" data-v-6c48fca3></div><div style="font-size:13px;font-weight:700;" data-v-6c48fca3>Dark surface</div><div class="mono" style="font-size:11.5px;color:var(--d-fg-muted);" data-v-6c48fca3>--surface-dark</div></div></div></div><h3 class="sub" data-v-6c48fca3>Accent families</h3><p data-v-6c48fca3>Within one theme, <b data-v-6c48fca3>the theme color (accent) can switch among several color families</b>. Two parallel families are provided today: <b data-v-6c48fca3>blue</b> (default, brand blue, carrying semantic emphasis) and <b data-v-6c48fca3>black</b> (neutral black, carrying the most restrained strong action). Both share the same components, fonts, radii, and surfaces — switching families only swaps the accent token set, with zero structural change; more families (green / purple, etc.) can be added later. The two cards below show the same <code data-v-6c48fca3>primary</code> button under the two families.</p><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Family switch · same primary, different theme color</span></div><div class="stage p col" data-v-6c48fca3><div class="demo-row" style="align-items:stretch;" data-v-6c48fca3><div class="demo-col" style="flex:1;border:1px solid var(--p-line);border-radius:12px;background:var(--p-surface-raised);padding:16px;gap:12px;" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>Blue family · default</span><div class="demo-row" data-v-6c48fca3><button class="p-btn primary sm" data-v-6c48fca3>Primary action</button><span class="p-badge info sm" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>accent</span></div><span class="mono" style="font-size:11px;color:var(--p-text-muted);" data-v-6c48fca3>--accent #1783ff · soft #e8f3ff</span></div><div class="demo-col demo-family-black" style="flex:1;border:1px solid var(--p-line);border-radius:12px;background:var(--p-surface-raised);padding:16px;gap:12px;" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>Black family · neutral</span><div class="demo-row" data-v-6c48fca3><button class="p-btn primary sm" data-v-6c48fca3>Primary action</button><span class="p-badge info sm" data-v-6c48fca3><span class="bd" data-v-6c48fca3></span>accent</span></div><span class="mono" style="font-size:11px;color:var(--p-text-muted);" data-v-6c48fca3>--accent #14171c · soft #f1f2f4</span></div></div></div></div><h3 class="sub" data-v-6c48fca3>Theme console · change 4 colors, light & dark change together</h3><div class="stage-wrap" data-v-6c48fca3><div class="stage-bar" data-v-6c48fca3><span class="st" data-v-6c48fca3>Theme Console</span></div><div class="stage p col" style="gap:18px;" data-v-6c48fca3><div class="demo-row" style="justify-content:center;gap:10px;flex-wrap:wrap;" data-v-6c48fca3><span class="p-badge info" data-v-6c48fca3><span style="width:10px;height:10px;border-radius:3px;background:#1783ff;" data-v-6c48fca3></span>Primary #1783ff</span><span class="p-badge neutral" data-v-6c48fca3><span style="width:10px;height:10px;border-radius:3px;background:#6b7280;" data-v-6c48fca3></span>Secondary #6b7280</span><span class="p-badge neutral" data-v-6c48fca3><span style="width:10px;height:10px;border-radius:3px;background:#ffffff;border:1px solid var(--p-line);" data-v-6c48fca3></span>Light surface #ffffff</span><span class="p-badge neutral" data-v-6c48fca3><span style="width:10px;height:10px;border-radius:3px;background:#0d1117;" data-v-6c48fca3></span>Dark surface #0d1117</span></div><div class="demo-row" style="align-items:stretch;" data-v-6c48fca3><div class="demo-col" style="flex:1;border:1px solid var(--p-line);border-radius:12px;background:var(--p-surface-raised);padding:16px;gap:10px;" data-v-6c48fca3><span class="stage-label" data-v-6c48fca3>Light surface preview</span><button class="p-btn primary sm" style="align-self:flex-start;" data-v-6c48fca3>Primary action</button><span style="font-size:12px;color:var(--p-text-muted);" data-v-6c48fca3>White background + accent button + neutral text</span></div><div class="demo-col" data-p="dark" style="flex:1;border:1px solid var(--p-line);border-radius:12px;background:var(--p-surface-raised);padding:16px;gap:10px;" data-v-6c48fca3><span class="stage-label" style="color:#9aa0a8;" data-v-6c48fca3>Dark surface preview</span><button class="p-btn primary sm" style="align-self:flex-start;" data-v-6c48fca3>Primary action</button><span style="font-size:12px;color:var(--p-text-muted);" data-v-6c48fca3>Dark background + same accent + derived text</span></div></div></div></div><h3 class="sub" data-v-6c48fca3>Light / dark mode</h3><p data-v-6c48fca3>Driven by the two surfaces <code data-v-6c48fca3>--surface-light</code> / <code data-v-6c48fca3>--surface-dark</code>: whichever surface is current derives the corresponding foreground, border, shadow, and status colors. Switching light / dark simply swaps between these two sets of derived tokens, with zero structural change.</p><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3><b data-v-6c48fca3>Benefits of one theme</b>: components, fonts, radii, and surfaces are consistent site-wide; reskinning only changes 4 color seeds; light / dark mode works out of the box; semantic status colors are independently tunable. </div></div></section><section id="rules" data-v-6c48fca3><div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>06</span><h2 class="sec-title" data-v-6c48fca3>Style Rules</h2></div><p class="sec-desc" data-v-6c48fca3> Anti-pattern rules that all UI code must follow. These rules are also the basis of the check-style detection script, one-to-one with a warning. </p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Rule ID</th><th data-v-6c48fca3>What it detects</th><th data-v-6c48fca3>Action</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-gradient-text</td><td data-v-6c48fca3>gradient text / gradient background</td><td data-v-6c48fca3><span class="pill red" data-v-6c48fca3>Forbidden</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-glassmorphism</td><td data-v-6c48fca3><code data-v-6c48fca3>backdrop-filter: blur</code> (<b data-v-6c48fca3>TopBar sticky nav bar</b> is the sole exception)</td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>TopBar exempt</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-color-glow</td><td data-v-6c48fca3>colored / large-radius box-shadow glow</td><td data-v-6c48fca3><span class="pill red" data-v-6c48fca3>Forbidden</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-emoji-icon</td><td data-v-6c48fca3>using emoji as a functional icon (<b data-v-6c48fca3>the moon phases 🌑…🌘 are the sole exception</b>, and only in the "waiting for the Agent to respond" chat state; all other loading states use the plain Spinner)</td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Moon phase exempt</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-hardcoded-hex</td><td data-v-6c48fca3>unregistered hex color inside a component <code data-v-6c48fca3><style></code></td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Warning</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>no-hardcoded-font</td><td data-v-6c48fca3>hard-coded <code data-v-6c48fca3>font-family</code> in a component (e.g. <code data-v-6c48fca3>'Inter'</code>) instead of <code data-v-6c48fca3>var(--font-ui)</code></td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Warning</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>radius-from-scale</td><td data-v-6c48fca3>radius value not in <code data-v-6c48fca3>{4,6,8,12,16,20,999}</code></td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Warning</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>z-from-scale</td><td data-v-6c48fca3>z-index using an unregistered large number</td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Warning</span></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>weight-from-scale</td><td data-v-6c48fca3>font-weight not in <code data-v-6c48fca3>{400,500}</code></td><td data-v-6c48fca3><span class="pill amber" data-v-6c48fca3>Warning</span></td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>State matrix</h3><p data-v-6c48fca3>Every interactive primitive should define the following states where applicable; missing ones are flagged by the style rules. <code data-v-6c48fca3>focus-visible</code> always uses <code data-v-6c48fca3>--p-focus-ring</code> (appears only on keyboard focus, see §08); <code data-v-6c48fca3>disabled</code> is uniformly <code data-v-6c48fca3>opacity:.5</code>.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>State</th><th data-v-6c48fca3>Button</th><th data-v-6c48fca3>Input</th><th data-v-6c48fca3>Card</th><th data-v-6c48fca3>Menu item</th><th data-v-6c48fca3>Switch</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>default</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>hover</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>active / pressed</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>focus-visible</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>✓</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>disabled</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>loading</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>selected / active</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>✓</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>error</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>readonly</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>✓</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td><td data-v-6c48fca3>—</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Moon phase exemption</h3><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3> The "🌑…🌘" moon-phase emoji are a brand signature of Dimi Web, <b data-v-6c48fca3>used only in the chat state of "message sent, waiting for the Agent's first response"</b>, and are rendered uniformly by the <code data-v-6c48fca3>MoonSpinner</code> component; waiting states such as <code data-v-6c48fca3>ActivityNotice</code> reuse it rather than implementing their own moon phase. It is the sole exception to the <code data-v-6c48fca3>no-emoji-icon</code> rule; all other loading states use the plain <code data-v-6c48fca3>Spinner</code>. </div></div><h3 class="sub" data-v-6c48fca3>Glassmorphism exemption</h3><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3><code data-v-6c48fca3>backdrop-filter: blur</code> is banned site-wide, with the <b data-v-6c48fca3>sole exception of the <code data-v-6c48fca3>.frost</code> variant of <code data-v-6c48fca3>TopBar</code></b> — and only in the one place of the "sticky navigation bar", used to stay readable over scrolling content. No other component (card, dialog, Toast, panel) may use glassmorphism; violations are flagged under <code data-v-6c48fca3>no-glassmorphism</code>. </div></div><div class="footer" data-v-6c48fca3><span data-v-6c48fca3>Dimi Web Design System · v1.0</span><span data-v-6c48fca3>The reference when changing the web UI</span></div></section><section id="shell" data-v-6c48fca3><div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>07</span><h2 class="sec-title" data-v-6c48fca3>App Shell & Sidebar</h2></div><p class="sec-desc" data-v-6c48fca3> The structural spec for the app shell (three-column grid + right preview panel) and the left session sidebar. These are business-agnostic "skeletons" — components, fonts, radii, and surfaces are reused from §02 / §03, but layout and alignment have their own conventions. </p><h3 class="sub" data-v-6c48fca3>Layout grid</h3><p data-v-6c48fca3>On desktop it is a single-row 5-track grid: the sidebar and the right panel each occupy a permanent <code data-v-6c48fca3>auto</code> track, with the conversation column in the middle; two 0-width tracks are for the ResizeHandles.</p><div class="code" data-v-6c48fca3><div class="code-bar" data-v-6c48fca3><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="d" data-v-6c48fca3></span><span class="fn" data-v-6c48fca3>App.vue · .app</span></div><pre data-v-6c48fca3>grid-template-columns: auto 0 minmax(0, 1fr) 0 auto;
|
|
13
|
+
/* sidebar ↑ ↑handle ↑conversation ↑handle ↑right panel (auto) */</pre></div><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>sidebar width</td><td class="val" data-v-6c48fca3>270px default (adjustable)</td><td data-v-6c48fca3>expanded sidebar width, changed by dragging the ResizeHandle; should approach §02's <code data-v-6c48fca3>--p-sidebar-w</code> (264px)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--preview-w</td><td class="val" data-v-6c48fca3>460px</td><td data-v-6c48fca3>width of the right preview panel when open</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--panel-head-h</td><td class="val" data-v-6c48fca3>48px</td><td data-v-6c48fca3>unified height for all right panel heads + the conversation column head, so the hairline runs as one line</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--p-bp-sm</td><td class="val" data-v-6c48fca3>640px</td><td data-v-6c48fca3>≤640 switches to a mobile single column (top bar + conversation), no sidebar / handle / right panel</td></tr></tbody></table><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>The right panel track exists permanently, with its width transitioning between <code data-v-6c48fca3>0 ↔ var(--preview-w)</code> (when open it squeezes the conversation column, rather than switching templates).</li><li data-v-6c48fca3>The sidebar collapses SYMMETRICALLY to the right panel: its container width animates to 0 while the content keeps its fixed width anchored to the right edge (clipped, sliding out left — no reflow, hairline stays on the clipped content). No rail remains. The collapse control differs by platform: on <b data-v-6c48fca3>macOS desktop</b> the toggle is a single resident floating IconButton pinned beside the traffic lights (rendered in both states, only the glyph swaps — the sidebar slides underneath it, never moves or flashes); on <b data-v-6c48fca3>Windows / web</b> the collapse button lives inside the sidebar header (right-aligned), and a floating expand button appears at the top-left only while collapsed. The conversation header pads left in step with the transition while collapsed.</li><li data-v-6c48fca3>All grid children must have <code data-v-6c48fca3>min-height:0; min-width:0</code>, so only the inner scroll containers scroll and the page itself does not scroll.</li></ul><h3 class="sub" data-v-6c48fca3>Sidebar alignment system (<code data-v-6c48fca3>--sb-*</code>)</h3><p data-v-6c48fca3>All sidebar rows (group head, session row, New chat button) share 4 custom properties, so the "session title" aligns precisely under the "workspace name".</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Token</th><th data-v-6c48fca3>Value</th><th data-v-6c48fca3>Usage</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--sb-inset</td><td class="val" data-v-6c48fca3>12px</td><td data-v-6c48fca3>row box (hover/selected pill) inset from the sidebar edges — matches the brand header's 12px padding</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--sb-pad-x</td><td class="val" data-v-6c48fca3>20px</td><td data-v-6c48fca3>content start x (= --sb-inset + 8px row padding)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--sb-gutter</td><td class="val" data-v-6c48fca3>16px</td><td data-v-6c48fca3>leading icon slot width — matches the workspace folder icon so the session title aligns under the workspace name</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>--sb-gap</td><td class="val" data-v-6c48fca3>6px</td><td data-v-6c48fca3>gap between the icon slot and the text</td></tr></tbody></table><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3> The session title's starting x = <code data-v-6c48fca3>--sb-pad-x + --sb-gutter + --sb-gap</code>. The group head has a folder icon and the session row has a status slot; both icons are the same width and position, so the titles align naturally. </div></div><h3 class="sub" data-v-6c48fca3>Sidebar structure</h3><p data-v-6c48fca3>The sidebar from top to bottom: brand header → New chat → search → grouped list (workspace head + session rows) → settings footer. Controls reuse the §03 primitives as much as possible. The sidebar sits on <code data-v-6c48fca3>--color-sidebar-bg</code> (one step off <code data-v-6c48fca3>--color-bg</code>: warm off-white in light, near-black in dark — the session column reads as its own plane; the hairline still separates it from the conversation pane). Vertical rhythm: the brand header keeps 12px padding (on macOS desktop the left padding grows to 80px to clear the traffic lights); rows inside the actions group (New chat + search) stack flush (0 gap, same rhythm as the list rows); adjacent groups are separated by 12px. Row hover uses <code data-v-6c48fca3>--sb-hover</code> (= the global <code data-v-6c48fca3>--color-hover</code> wash); the selected row uses <code data-v-6c48fca3>--color-selected</code> — neutral, never the accent.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Block</th><th data-v-6c48fca3>Use</th><th data-v-6c48fca3>Note</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td data-v-6c48fca3>Brand header</td><td data-v-6c48fca3>logo + name + collapse IconButton (right-aligned)</td><td data-v-6c48fca3>on Windows / web the brand is left and the collapse IconButton sm is right-aligned inside the header; the logo is animated (a blinking eye). On macOS desktop the header is a bare drag strip (brand hidden, traffic lights + resident floating toggle over it)</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>New chat</td><td data-v-6c48fca3>full-width left-aligned button (custom)</td><td data-v-6c48fca3>same rhythm as the session rows in the list (left-aligned, hover = <code data-v-6c48fca3>--sb-hover</code>). <b data-v-6c48fca3>Do not</b> use Button (centered, breaks the rhythm)</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Search</td><td data-v-6c48fca3>bare search row (custom)</td><td data-v-6c48fca3>no border, hover/focus shows a sunken background; icon + label, with the <code data-v-6c48fca3>Kbd</code> keycaps (⌘K / Ctrl K) pushed to the trailing edge — label and shortcut are justified apart. <b data-v-6c48fca3>Do not</b> use Input (the 38px bordered version is too heavy). Last fixed row above the list — its wrapper carries the scroll-linked seam</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Section label</td><td data-v-6c48fca3><code data-v-6c48fca3>.p-section-label</code></td><td data-v-6c48fca3>uppercase muted small titles like "Workspaces"</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Workspace head / session row</td><td data-v-6c48fca3>see next two sections</td><td data-v-6c48fca3>share <code data-v-6c48fca3>--sb-*</code> alignment</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Settings footer</td><td data-v-6c48fca3>full-width left-aligned button (custom)</td><td data-v-6c48fca3>pinned row under the session list, separated by a 1px <code data-v-6c48fca3>--line</code> top border; icon + label, same list-style family as New chat</td></tr></tbody></table><div class="callout warn" data-v-6c48fca3><span class="ico" data-v-6c48fca3>!</span><div data-v-6c48fca3><b data-v-6c48fca3>Why New chat / search / inline rename don't use Button / Input:</b> they are "list-style" controls (full-width, left-aligned, compact, borderless), while Button is centered and Input is a 38px bordered control — forcing them in would break the sidebar's visual density and alignment. This is an intentional custom exception, not an oversight. </div></div><h3 class="sub" data-v-6c48fca3>Session row</h3><p data-v-6c48fca3>A session row is an inset rounded pill, structured as: <code data-v-6c48fca3>status slot → title → time → attention Badge → kebab</code>.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Part</th><th data-v-6c48fca3>Rule</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td data-v-6c48fca3>Container</td><td data-v-6c48fca3><code data-v-6c48fca3>padding: 8px 8px</code> inside the list's <code data-v-6c48fca3>--sb-inset</code> gutter, <code data-v-6c48fca3>radius-sm</code>; <b data-v-6c48fca3>no fixed/min height</b> — row height is font-driven (title <code data-v-6c48fca3>line-height: --leading-tight</code>, ≈16px) → ≈32px total, the sidebar-wide row rhythm. The hover kebab is absolutely positioned so it never forces the row taller (no hover jitter). hover = <code data-v-6c48fca3>--sb-hover</code> (the global <code data-v-6c48fca3>--color-hover</code> wash); active = <code data-v-6c48fca3>--color-selected</code> — neutral, no accent tint, no border, no weight change</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Status slot (lead)</td><td data-v-6c48fca3>fixed <code data-v-6c48fca3>--sb-gutter</code> width; running = <code data-v-6c48fca3>Spinner</code> sm, otherwise unread = 7px accent dot</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Title</td><td data-v-6c48fca3>flex:1 with truncation; double-click enters inline rename (compact input, not Input)</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Time</td><td data-v-6c48fca3>mono xs, <code data-v-6c48fca3>fg-faint</code>; yields to the kebab on hover</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Attention Badge</td><td data-v-6c48fca3><code data-v-6c48fca3>Badge</code> sm: info (needs answer) / warning (needs approval) / danger (aborted)</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>kebab</td><td data-v-6c48fca3><code data-v-6c48fca3>IconButton</code> sm, shown on hover; dropdown uses <code data-v-6c48fca3>Menu/MenuItem</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Archive confirmation</td><td data-v-6c48fca3>replaces the title area, <code data-v-6c48fca3>Button</code> sm (danger confirm / secondary cancel)</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Workspace group</h3><p data-v-6c48fca3>The group head and session rows share <code data-v-6c48fca3>--sb-*</code>: folder icon (open/closed) → name, with the kebab and "+" revealed on hover.</p><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>The folder icon leads the row (switching icons between open and closed states) with the plain <code data-v-6c48fca3>--sb-gap</code> before the name — it does not pad out the <code data-v-6c48fca3>--sb-gutter</code> slot.</li><li data-v-6c48fca3>The name is quiet by design — regular weight, muted color (<code data-v-6c48fca3>--color-text-muted</code>, one step lighter than session titles), so group heads read as grouping labels. No path subtitle; hovering the name shows the full root path in a <code data-v-6c48fca3>Tooltip</code>.</li><li data-v-6c48fca3>The kebab (menu) and "+" (new chat in this workspace) both use <code data-v-6c48fca3>IconButton</code> sm inside a floating actions layer anchored to the row's right edge — no reserved layout space, so the name uses the full row width when idle. Shown on hover, keyboard focus, or while the menu is open; the layer backs itself with the sidebar surface (container background) plus the row hover wash (an <code data-v-6c48fca3>::after</code> shown only while the row is hovered), so its color exactly equals the row's current background and the overlapped name tail doesn't bleed through (hidden via <code data-v-6c48fca3>opacity:0</code>, staying in the tab order).</li><li data-v-6c48fca3>The group is collapsible; when collapsed its session list is hidden.</li></ul><h3 class="sub" data-v-6c48fca3>Show more & collapse</h3><p data-v-6c48fca3>The "load more / show less" control at the bottom of each workspace group is a session-row-shaped compact list control (same family as search, New chat, inline rename — not a Button). It doubles as the pagination trigger and the in-group expand / collapse toggle.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Part</th><th data-v-6c48fca3>Rule</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Container</td><td data-v-6c48fca3>session-row pill: <code data-v-6c48fca3>display:flex; gap:--sb-gap; padding:8px …</code>, <b data-v-6c48fca3>no fixed/min height</b> (font-driven, ≈32px like a session row), same padding as a session row, <code data-v-6c48fca3>radius-sm</code>; hover = <code data-v-6c48fca3>--sb-hover</code> (no text recolor); <code data-v-6c48fca3>:focus-visible</code> uses <code data-v-6c48fca3>--p-focus-ring</code></td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Lead slot</td><td data-v-6c48fca3>empty, <code data-v-6c48fca3>--sb-gutter</code> wide, so the label's start x aligns with the session titles (<code data-v-6c48fca3>--sb-pad-x + --sb-gutter + --sb-gap</code>)</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Label</td><td data-v-6c48fca3><code data-v-6c48fca3>font-ui</code>, <code data-v-6c48fca3>text-xs</code>, <code data-v-6c48fca3>--color-text</code>; flex:1, truncated</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Behavior</td><td data-v-6c48fca3>"Load more" fetches the next page and auto-expands; once more than the first page is loaded, "Show less" appears and collapses back to the first page (view-layer trim — data is kept, no refetch); "Show all" re-expands</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>ResizeHandle</h3><p data-v-6c48fca3>A 4px vertical drag bar, layered over the 1px column border (<code data-v-6c48fca3>margin: 0 -2px</code> makes the whole 4px grabbable), turning accent on hover / drag.</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Rule</th><th data-v-6c48fca3>Value</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td data-v-6c48fca3>Width / cursor</td><td data-v-6c48fca3>4px / <code data-v-6c48fca3>col-resize</code></td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Normal / active</td><td data-v-6c48fca3>transparent / <code data-v-6c48fca3>accent</code> fill</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Layer</td><td data-v-6c48fca3><code data-v-6c48fca3>--z-dropdown</code>, above pane-level sticky chrome (chat dock at <code data-v-6c48fca3>--z-sticky</code>) so the overhang stays visible and grabbable</td></tr><tr data-v-6c48fca3><td data-v-6c48fca3>Behavior</td><td data-v-6c48fca3>panel width follows the pointer 1:1 while dragging (the parent disables transitions to avoid lag); on release it is persisted to localStorage</td></tr></tbody></table><h3 class="sub" data-v-6c48fca3>Right panel</h3><p data-v-6c48fca3>The right panels (file preview / Diff / thinking / sub-agent / side chat) share one track and one head primitive.</p><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>The panel head uses the <code data-v-6c48fca3>PanelHeader</code> primitive (48px = <code data-v-6c48fca3>--panel-head-h</code>), the same height as the conversation column head, so the hairline runs as one line.</li><li data-v-6c48fca3>Panel head: bold mono title + optional muted subtitle + middle slot (Badge / control / path) + close IconButton on the right.</li><li data-v-6c48fca3>When opened, the panel width goes from <code data-v-6c48fca3>0 → var(--preview-w)</code>, smoothly squeezing the conversation column.</li><li data-v-6c48fca3>At ≤640px the panel becomes a full-screen overlay (<code data-v-6c48fca3>position:fixed; inset:0</code>).</li></ul><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>One-sentence principle:</b> the sidebar / shell is a "list + grid" skeleton that reuses the §02 tokens and §03 primitives (Button / IconButton / Badge / Kbd / Menu / Spinner / PanelHeader); compact list controls that don't fit a primitive (search, New chat, inline rename, show-more) keep their custom form, governed by this section. </div></div></section><section id="a11y" data-v-6c48fca3><div class="sec-head" data-v-6c48fca3><span class="sec-num" data-v-6c48fca3>08</span><h2 class="sec-title" data-v-6c48fca3>Accessibility (pragmatic edition)</h2></div><p class="sec-desc" data-v-6c48fca3> Dimi Web is a local developer tool; it <b data-v-6c48fca3>does not target a specific WCAG conformance level</b>, nor maintain a full screen-reader QA matrix. This section collects only the rules that are "low-cost, don't hurt the look, and directly benefit keyboard-heavy users", as the baseline contract for each primitive; the more expensive, lower-ROI parts (such as real-time announcement orchestration for streaming output) are not mandatory for now. </p><div class="callout info" data-v-6c48fca3><span class="ico" data-v-6c48fca3>i</span><div data-v-6c48fca3><b data-v-6c48fca3>On the "ugly" focus ring:</b> the focus visibility required below always uses <code data-v-6c48fca3>:focus-visible</code> (not <code data-v-6c48fca3>:focus</code>). It appears <b data-v-6c48fca3>only on keyboard focus</b>; mouse clicks don't trigger it, so it doesn't pollute the mouse-driven visual; the ring's strength is tuned uniformly with <code data-v-6c48fca3>--p-focus-ring</code>, not overridden per place. </div></div><h4 class="mini" data-v-6c48fca3>1. Contrast & color</h4><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>Body text vs. background contrast <b data-v-6c48fca3>≥ 4.5:1</b>; control borders, icons, and key graphics <b data-v-6c48fca3>≥ 3:1</b>. When changing theme colors / dark mode, verify against §05 together.</li><li data-v-6c48fca3><b data-v-6c48fca3>Button text vs. button background</b>, and <b data-v-6c48fca3>form controls</b> (input, placeholder, helper / error text) <b data-v-6c48fca3>vs. their section background</b> must all have contrast ≥ 4.5:1 (large text ≥ 3:1). White-on-white text, a transparent borderless button floating over the page background, and a light placeholder on a near-white background are all flagged by the style rules.</li><li data-v-6c48fca3><b data-v-6c48fca3>State is not conveyed by color alone.</b> Error, selected, and disabled states also carry text, an icon, or a shape change (for example an error state is not just red, but also carries text or an icon).</li></ul><h4 class="mini" data-v-6c48fca3>2. Keyboard operable</h4><p data-v-6c48fca3>Anything doable with a mouse must also be doable with a keyboard; Tab order follows the DOM, with no invented skipping. Composite controls define their keyboard model per the table below; a missing model is treated as incomplete:</p><table class="dt" data-v-6c48fca3><thead data-v-6c48fca3><tr data-v-6c48fca3><th data-v-6c48fca3>Control</th><th data-v-6c48fca3>Keyboard behavior</th></tr></thead><tbody data-v-6c48fca3><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Dialog</td><td data-v-6c48fca3><code data-v-6c48fca3>Tab</code> cycles within the dialog (focus trap); <code data-v-6c48fca3>Esc</code> closes; focus returns to the trigger element after closing.</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Menu</td><td data-v-6c48fca3><code data-v-6c48fca3>↑</code> / <code data-v-6c48fca3>↓</code> move the highlight, <code data-v-6c48fca3>Enter</code> selects, <code data-v-6c48fca3>Esc</code> closes.</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Tabs</td><td data-v-6c48fca3><code data-v-6c48fca3>←</code> / <code data-v-6c48fca3>→</code> switch tabs (roving tabindex); only the current tab is in the Tab sequence.</td></tr><tr data-v-6c48fca3><td class="tk" data-v-6c48fca3>Switch / Segmented</td><td data-v-6c48fca3><code data-v-6c48fca3>←</code> / <code data-v-6c48fca3>→</code> or <code data-v-6c48fca3>Space</code> / <code data-v-6c48fca3>Enter</code> to toggle.</td></tr></tbody></table><h4 class="mini" data-v-6c48fca3>3. Focus visibility</h4><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3>Every interactive element must have a visible focus indicator on keyboard focus, uniformly via <code data-v-6c48fca3>:focus-visible</code> + <code data-v-6c48fca3>--p-focus-ring</code> (primary actions may use <code data-v-6c48fca3>--p-focus-ring-strong</code>).</li><li data-v-6c48fca3>Bare <code data-v-6c48fca3>outline: none</code> is forbidden. To remove the default outline, you must provide an equivalent replacement style.</li></ul><h4 class="mini" data-v-6c48fca3>4. Labels & semantics</h4><ul class="clean" data-v-6c48fca3><li data-v-6c48fca3><b data-v-6c48fca3>Semantic HTML first</b> (button / a / input / dialog…); ARIA is added only when native semantics fall short.</li><li data-v-6c48fca3>Icon-only buttons must have an <code data-v-6c48fca3>aria-label</code> — <code data-v-6c48fca3>IconButton</code> already enforces this with a required <code data-v-6c48fca3>label</code> prop.</li><li data-v-6c48fca3>Dialog: <code data-v-6c48fca3>role="dialog"</code> + <code data-v-6c48fca3>aria-modal="true"</code>, with the title as the dialog's accessible name.</li><li data-v-6c48fca3>Purely decorative SVG / icons get <code data-v-6c48fca3>aria-hidden="true"</code> to avoid being read out by screen readers.</li></ul><h4 class="mini" data-v-6c48fca3>5. Target size</h4><p data-v-6c48fca3>Desktop click targets <b data-v-6c48fca3>≥ 32px</b>; touch devices <b data-v-6c48fca3>≥ 44px</b> (consistent with the §01 principle and the IconButton <code data-v-6c48fca3>lg</code> tier).</p><h4 class="mini" data-v-6c48fca3>6. Reduced motion</h4><p data-v-6c48fca3>Handled uniformly in the global styles per §02's <code data-v-6c48fca3>@media (prefers-reduced-motion: reduce)</code>; components do not check this individually. The MoonSpinner moon phase pauses on the current frame.</p><h4 class="mini" data-v-6c48fca3>7. Live announcements (non-mandatory)</h4><p data-v-6c48fca3>Screen-reader announcements are <b data-v-6c48fca3>not a mandatory contract</b> in this product. Short hints like Toast can use <code data-v-6c48fca3>role="status"</code> / <code data-v-6c48fca3>aria-live</code>; chat streaming output is currently not announced word-by-word, which is an acceptable trade-off, to be added later if a real need arises.</p><div class="callout good" data-v-6c48fca3><span class="ico" data-v-6c48fca3>✓</span><div data-v-6c48fca3><b data-v-6c48fca3>Explicitly not mandatory for now:</b> a WCAG conformance-level claim, a complete ARIA pattern table, a per-screen-reader QA matrix, and real-time announcement orchestration for streaming output — these are not written into the primitive contract, to avoid becoming slogans no one maintains. </div></div></section>`,4))])])])]))}}),pa=S(va,[["__scopeId","data-v-6c48fca3"]]);export{pa as default};
|