lampson 0.1.2 → 0.1.4

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.
Files changed (49) hide show
  1. package/.env.example +9 -0
  2. package/README.md +60 -2
  3. package/chat.syn +264 -9
  4. package/lampson.ps1 +17 -3
  5. package/lampson.sh +17 -3
  6. package/lib/agents.syn +1 -1
  7. package/lib/approvals.syn +176 -0
  8. package/lib/diff.syn +37 -11
  9. package/lib/line.syn +13 -8
  10. package/lib/loop.syn +25 -11
  11. package/lib/md.syn +76 -18
  12. package/lib/permission.syn +18 -0
  13. package/lib/prompt.syn +1 -1
  14. package/lib/sched_run.syn +161 -0
  15. package/lib/schedule.syn +660 -0
  16. package/lib/session.syn +38 -1
  17. package/lib/settings.syn +55 -0
  18. package/lib/tools.syn +94 -2
  19. package/lib/ui.syn +161 -0
  20. package/package.json +1 -1
  21. package/public/css/chat.css +56 -0
  22. package/public/css/layout.css +97 -0
  23. package/public/css/panel.css +125 -0
  24. package/public/css/sidebar.css +80 -0
  25. package/public/css/tokens.css +57 -0
  26. package/public/index.html +49 -1187
  27. package/public/js/agents.js +31 -0
  28. package/public/js/app.js +21 -0
  29. package/public/js/approvals.js +26 -0
  30. package/public/js/chat.js +92 -0
  31. package/public/js/config.js +98 -0
  32. package/public/js/core.js +88 -0
  33. package/public/js/events.js +31 -0
  34. package/public/js/lamps.js +112 -0
  35. package/public/js/lsp.js +81 -0
  36. package/public/js/mcp.js +74 -0
  37. package/public/js/memory.js +17 -0
  38. package/public/js/panel.js +101 -0
  39. package/public/js/procs.js +45 -0
  40. package/public/js/schedules.js +118 -0
  41. package/public/js/sessions.js +69 -0
  42. package/public/js/sidebar.js +33 -0
  43. package/public/js/terminal.js +49 -0
  44. package/public/js/theme.js +6 -0
  45. package/public/js/todo.js +10 -0
  46. package/public/js/tree.js +53 -0
  47. package/public/js/update.js +14 -0
  48. package/skills/lampson/SKILL.md +16 -0
  49. package/web.syn +106 -15
@@ -0,0 +1,125 @@
1
+ /* panel: EL componente modal de la app (js/panel.js). Un cascarón (overlay, cabecera, ✕/Esc/clic afuera) y
2
+ tres layouts: browse (buscador + lista + detalle), tabs (pestañas con formularios) y form (un formulario).
3
+ Cada vista (sesiones, lámparas, configuración, programar…) solo aporta su contenido; nada de esto se repite. */
4
+ .modal { position:fixed; inset:0; background:rgba(0,0,0,.45); display:flex; align-items:center; justify-content:center; z-index:50; }
5
+ .panel { background:var(--paper); border:1px solid var(--rule-2); border-radius:var(--r); box-shadow:0 10px 30px rgba(0,0,0,.35); display:flex; flex-direction:column; min-height:0; max-height:92vh; }
6
+ .panel.lg { width:min(1100px, 94vw); height:min(760px, 90vh); padding:14px 18px 12px; }
7
+ .panel.md { width:min(680px, 94vw); padding:14px 18px 12px; }
8
+ .panel.sm { width:min(560px, 92vw); padding:14px 18px 12px; }
9
+
10
+ /* cabecera */
11
+ .panel .phead { display:flex; align-items:center; gap:12px; padding-bottom:10px; border-bottom:1px solid var(--rule); flex:none; }
12
+ .panel .phead .eyebrow { font:400 10.5px/1 var(--mono); text-transform:uppercase; letter-spacing:.12em; color:var(--rubric); margin:0; }
13
+ .panel .phead h3 { margin:0; font:600 16px/1.2 var(--serif); letter-spacing:-.01em; }
14
+ .panel .phead .sub { color:var(--ink-3); font:400 11.5px/1 var(--mono); }
15
+ .panel .pghost { display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; padding:0; margin:0; font:400 13px/1 var(--mono); letter-spacing:0; text-transform:none; border:1px solid var(--rule); border-radius:var(--r); background:transparent; color:var(--ink-3); cursor:pointer; }
16
+ .panel .pghost:hover { color:var(--ink); border-color:var(--rule-2); }
17
+ .panel .pghost + .pghost { margin-left:6px; }
18
+
19
+ /* pestañas */
20
+ .panel .ptabs { display:flex; gap:2px; border-bottom:1px solid var(--rule); margin:0 0 14px; flex:none; }
21
+ .panel .ptab { font:400 11px/1 var(--mono); text-transform:uppercase; letter-spacing:.08em; color:var(--ink-3); padding:10px 12px 8px; cursor:pointer; border-bottom:2px solid transparent; margin-bottom:-1px; }
22
+ .panel .ptab:hover { color:var(--ink); }
23
+ .panel .ptab.on { color:var(--accent); border-bottom-color:var(--accent); }
24
+
25
+ /* cuerpo genérico (form / tabs): prosa y campos con la gramática de la app */
26
+ .panel .pbody { flex:1; min-height:0; overflow:auto; padding:14px 2px 4px; }
27
+ .panel .lead { color:var(--ink-2); margin:0 0 16px; font-size:14px; }
28
+ .panel .lead code, .panel .phelp code { font:400 .88em/1.5 var(--mono); background:var(--paper-2); padding:.08em .3em; border-radius:2px; color:var(--ink); }
29
+ .panel label { display:flex; align-items:center; gap:12px; font:400 10.5px/1 var(--mono); text-transform:uppercase; letter-spacing:.1em; color:var(--ink-3); margin:0 0 10px; }
30
+ .panel label.col { flex-direction:column; align-items:stretch; gap:4px; }
31
+ .panel label .ds { display:block; color:var(--ink-3); font:400 11.5px/1.4 var(--serif); text-transform:none; letter-spacing:0; margin-top:2px; }
32
+ .panel input, .panel select, .panel textarea { flex:1; font:400 13px/1.4 var(--mono); color:var(--ink); background:var(--paper-2); border:1px solid var(--rule); border-radius:var(--r); padding:7px 10px; min-width:0; }
33
+ .panel input:focus, .panel select:focus, .panel textarea:focus { outline:none; border-color:var(--rule-2); box-shadow:0 0 0 3px var(--accent-bg); }
34
+ .panel input[disabled] { opacity:.55; }
35
+ .panel textarea { width:100%; resize:vertical; font:400 12.5px/1.45 var(--mono); }
36
+ .panel .pfoot { display:flex; gap:8px; align-items:center; margin-top:14px; flex:none; }
37
+ .panel .err { color:var(--rubric); font:400 12px/1.4 var(--mono); min-height:14px; }
38
+ .panel .plist { border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); max-height:40vh; overflow:auto; margin:0 0 14px; }
39
+ .panel .plist .pr { display:flex; align-items:center; gap:10px; padding:7px 10px; cursor:pointer; font:400 12.5px/1.4 var(--mono); color:var(--ink-2); border-left:2px solid transparent; }
40
+ .panel .plist .pr:hover { color:var(--ink); }
41
+ .panel .plist .pr.on { color:var(--ink); border-left-color:var(--accent); background:var(--paper-2); }
42
+ .panel .plist .pr b { width:110px; font-weight:600; color:var(--ink); }
43
+ .panel .plist .pr .dm { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ink-3); }
44
+ .panel .plist .pr .k { font-size:11px; color:var(--str); }
45
+ .panel .plist .pr .k.no { color:var(--ink-3); }
46
+
47
+ /* browse: lista a la izquierda (buscador, filas, contador), detalle a la derecha. Un scroll por columna, nunca horizontal. */
48
+ .panel .browse { flex:1; min-height:0; display:grid; grid-template-columns:var(--list-w, 300px) minmax(0,1fr); }
49
+ .panel .blist { display:flex; flex-direction:column; border-right:1px solid var(--rule); padding:10px 12px 8px 0; min-height:0; min-width:0; }
50
+ .panel .blist input { flex:none; height:30px; font:400 12px/1.4 var(--mono); background:transparent; padding:0 8px; margin:0 0 8px; width:100%; }
51
+ .panel .bitems { flex:1; overflow-y:auto; overflow-x:hidden; min-height:0; }
52
+ .panel .bcount { color:var(--ink-3); font:400 11px/1 var(--mono); padding-top:8px; border-top:1px solid var(--rule); flex:none; }
53
+ .panel .bdetail { overflow-y:auto; overflow-x:hidden; min-height:0; min-width:0; padding:12px 6px 8px 18px; font:400 12.5px/1.5 var(--mono); }
54
+ .panel .bempty { color:var(--ink-3); font:400 12.5px/1.5 var(--serif); padding:8px; }
55
+ .panel .li { display:grid; grid-template-columns:14px minmax(0,1fr); gap:8px; align-items:start; padding:7px 8px; border-radius:var(--r); cursor:pointer; font:400 12px/1.35 var(--mono); min-width:0; }
56
+ .panel .li.nodot { grid-template-columns:minmax(0,1fr); }
57
+ .panel .li > div { min-width:0; }
58
+ .panel .li:hover { background:var(--paper-2); }
59
+ .panel .li.sel { background:var(--paper-2); box-shadow:inset 2px 0 0 var(--accent); }
60
+ .panel .li .dot { color:var(--ink-3); margin-top:1px; }
61
+ .panel .li.on .dot { color:var(--accent); }
62
+ .panel .li.bad .dot { color:var(--rubric); }
63
+ .panel .li.new .nm { color:var(--accent); font-weight:400; }
64
+ .panel .dform label { margin-top:10px; }
65
+ .panel .dform .lead { margin:8px 0 12px; }
66
+ .panel .dform .pfoot { margin-top:16px; }
67
+ .panel .derr { color:var(--rubric); font:400 12px/1.4 var(--mono); min-height:14px; margin-top:6px; }
68
+ .panel .dlog { margin-top:12px; max-height:38vh; overflow:auto; font:400 11.5px/1.45 var(--mono); border:1px solid var(--rule); border-radius:var(--r); padding:8px; white-space:pre-wrap; color:var(--ink-2); }
69
+ .panel .li.broken .dot { color:var(--rubric); }
70
+ .panel .li .nm { color:var(--ink); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
71
+ .panel .li .nm.serif { font:400 13px/1.35 var(--serif); }
72
+ .panel .li .meta { color:var(--ink-3); font-size:11px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
73
+ .panel .li .snip { color:var(--ink-2); font:400 12px/1.4 var(--serif); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
74
+ .panel mark { background:transparent; color:var(--accent); font-weight:600; }
75
+
76
+ /* piezas de detalle que comparten las vistas */
77
+ .panel .dhead { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
78
+ .panel .dhead .nm { font:600 18px/1.2 var(--mono); color:var(--ink); }
79
+ .panel .dhead .nm.serif { font:600 16px/1.3 var(--serif); }
80
+ .panel .dhead .meta { color:var(--ink-3); font-size:11.5px; }
81
+ .panel .ddesc { color:var(--ink-2); font:400 13px/1.5 var(--serif); margin:8px 0 4px; max-width:70ch; }
82
+ .panel .dcap { color:var(--ink-3); font-size:11.5px; margin-bottom:12px; word-break:break-all; }
83
+ .panel .dcap b { color:var(--rubric); font-weight:600; }
84
+ .panel .dcap.err { color:var(--rubric); }
85
+ .panel .dnote { color:var(--ink-3); font:400 12px/1.5 var(--serif); border:1px dashed var(--rule-2); border-radius:var(--r); padding:8px 10px; margin:8px 0 12px; }
86
+ .panel .dacts { display:flex; gap:8px; margin-top:12px; }
87
+ .panel .dacts button { font:400 12px/1 var(--mono); padding:6px 12px; }
88
+ .panel .dfoot { display:flex; align-items:center; gap:12px; margin-top:14px; padding-top:10px; border-top:1px solid var(--rule); color:var(--ink-3); font-size:11.5px; }
89
+ .panel .dfoot .del { margin-left:auto; cursor:pointer; color:var(--rubric); }
90
+ .panel .dfoot .del.ask .yes { color:var(--rubric); cursor:pointer; font-weight:600; }
91
+ .panel .dfoot .del.ask .no { cursor:pointer; }
92
+ .panel .none { color:var(--ink-3); font:400 13px/1.6 var(--serif); max-width:520px; }
93
+ /* switch encendido/apagado (lámparas) */
94
+ .panel label.sw { display:inline-flex; align-items:center; margin:0 0 0 auto; gap:6px; cursor:pointer; user-select:none; font:400 11.5px/1 var(--mono); text-transform:none; letter-spacing:0; color:var(--ink-3); }
95
+ .panel label.sw input { flex:none; width:16px; height:16px; padding:0; margin:0; accent-color:var(--accent); }
96
+ .panel label.sw.on { color:var(--accent); }
97
+ /* formulario generado desde un JSON Schema (tools de una lámpara) */
98
+ .panel .tool { border:1px solid var(--rule); border-radius:var(--r); padding:10px 12px; margin-bottom:10px; }
99
+ .panel .tool .th { display:grid; grid-template-columns:auto 1fr auto; gap:8px 10px; align-items:baseline; }
100
+ .panel .tool .th code { font-weight:600; color:var(--ink); }
101
+ .panel .tool .th .ds { color:var(--ink-3); font:400 12px/1.4 var(--serif); }
102
+ .panel label.lf { display:grid; grid-template-columns:120px minmax(0,1fr); gap:2px 10px; align-items:center; margin:8px 0 0; font:400 12px/1.4 var(--mono); text-transform:none; letter-spacing:0; color:var(--ink); }
103
+ .panel label.lf .lk { color:var(--ink); }
104
+ .panel label.lf .req { color:var(--rubric); font-size:10.5px; }
105
+ .panel label.lf .ds { grid-column:2; color:var(--ink-3); font:400 11.5px/1.4 var(--serif); }
106
+ .panel label.lf input, .panel label.lf select, .panel label.lf textarea { flex:none; width:100%; max-width:420px; padding:4px 6px; font:400 12px/1.4 var(--mono); background:transparent; }
107
+ .panel label.lf textarea { grid-column:2; min-height:56px; }
108
+ .panel .tool .go { margin-top:10px; display:flex; align-items:center; gap:10px; }
109
+ .panel .tool .go button { font:400 12px/1 var(--mono); padding:5px 10px; }
110
+ .panel .tool .go .st { color:var(--ink-3); font-size:11.5px; }
111
+ .panel .tool pre.out { margin-top:8px; max-height:38vh; overflow:auto; font:400 11.5px/1.45 var(--mono); border:1px solid var(--rule); border-radius:var(--r); padding:8px; white-space:pre-wrap; }
112
+ /* conversación resumida (sesiones) */
113
+ .panel .dmsgs { margin-top:12px; display:flex; flex-direction:column; gap:8px; }
114
+ .panel .dmsg { border-left:2px solid var(--rule-2); padding:2px 0 2px 10px; font:400 12.5px/1.5 var(--serif); color:var(--ink-2); white-space:pre-wrap; word-break:break-word; }
115
+ .panel .dmsg.dm-user { border-left-color:var(--accent); color:var(--ink); }
116
+ .panel .dmsg.dm-bad { border-left-color:var(--rubric); }
117
+ .panel .dmsg .who a { color:var(--accent); text-decoration:none; }
118
+ .panel .dmsg .who { font:400 10.5px/1 var(--mono); text-transform:uppercase; letter-spacing:.08em; color:var(--ink-3); display:block; margin-bottom:3px; }
119
+ /* ayuda («?»): prosa a lo ancho, reemplaza al cuerpo */
120
+ .panel .phelp { flex:1; min-height:0; overflow:auto; padding:16px 24px 8px 6px; font:400 13.5px/1.6 var(--serif); color:var(--ink-2); }
121
+ .panel .phelp h4 { margin:0 0 8px; font:600 15px/1.3 var(--serif); color:var(--ink); }
122
+ .panel .phelp b { color:var(--ink); font-weight:600; }
123
+ .panel .phelp p { margin:0 0 12px; max-width:78ch; }
124
+ .panel .phelp ul { margin:0 0 16px 20px; padding:0; display:grid; gap:4px; max-width:78ch; }
125
+ .panel .phelp button { text-transform:none; letter-spacing:0; font:400 12px/1 var(--mono); padding:6px 10px; }
@@ -0,0 +1,80 @@
1
+ /* sidebar: secciones acordeón y las filas de cada una */
2
+ /* secciones colapsables; el activo es una muesca en la regla, no una caja */
3
+ .sec { display:flex; flex-direction:column; min-height:0; flex:none; overflow:hidden; }
4
+ .sec + .sec { border-top:1px solid var(--rule); }
5
+ .sec h2 { font:400 10.5px/1.35 var(--mono); text-transform:uppercase; letter-spacing:.1em; color:var(--ink-3); margin:0; padding:12px 16px 8px; display:flex; align-items:center; gap:8px; cursor:pointer; user-select:none; flex:none; }
6
+ .sec h2:hover { color:var(--ink); }
7
+ .sec .caret { width:9px; font-size:9px; color:var(--ink-3); }
8
+ .sec h2 .h2act { margin-left:auto; border:0; background:none; color:var(--ink-3); font:inherit; font-size:12px; cursor:pointer; padding:0 2px; line-height:1; opacity:.6; }
9
+ .sec h2 .h2act:hover { opacity:1; color:var(--accent); }
10
+ .sec h2 .h2act.spin { animation: h2spin .6s linear; }
11
+ @keyframes h2spin { to { transform: rotate(360deg); } }
12
+ .sec .cnt { margin-left:auto; letter-spacing:0; text-transform:none; }
13
+ .sec .body { display:none; overflow:auto; min-height:0; padding:0 10px 10px 16px; }
14
+ .sec.open .body { display:block; }
15
+ .sec:not(.grow).open .body { max-height:22vh; }
16
+ .sec.grow.open { flex:1; }
17
+ .sec.grow.open .body { flex:1; }
18
+ #tree { font:400 12.5px/1.5 var(--mono); }
19
+ .node { user-select:none; }
20
+ .row { display:flex; align-items:center; gap:6px; padding:3px 6px 3px 8px; cursor:pointer; color:var(--ink-2); white-space:nowrap; margin-left:-1px; border-left:2px solid transparent; }
21
+ .row:hover { color:var(--ink); }
22
+ .row.dir { color:var(--ink); }
23
+ .row .tw { width:9px; color:var(--ink-3); font-size:9px; }
24
+ .row.active { color:var(--ink); font-weight:600; border-left-color:var(--accent); }
25
+ .row.gM > span:nth-child(2) { color:var(--amber); }
26
+ .row.gA > span:nth-child(2), .row.gU > span:nth-child(2) { color:var(--str); }
27
+ .row.gD > span:nth-child(2) { color:var(--rubric); text-decoration:line-through; }
28
+ .row .gs { margin-left:auto; font-size:10px; color:var(--ink-3); }
29
+ .kids { margin-left:12px; border-left:1px solid var(--rule); }
30
+ .kids.hidden { display:none; }
31
+ .s, .m, .p { display:flex; align-items:center; gap:8px; padding:4px 6px 4px 8px; cursor:pointer; color:var(--ink-2); font:400 12.5px/1.5 var(--mono); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-left:-1px; border-left:2px solid transparent; }
32
+ .s:hover, .m:hover, .p:hover { color:var(--ink); }
33
+ .s.active, .m.active, .p.active { color:var(--ink); border-left-color:var(--accent); }
34
+ .s .title { overflow:hidden; text-overflow:ellipsis; font-family:var(--serif); font-size:13px; }
35
+ .s .id { color:var(--ink-3); font-size:11px; flex:none; }
36
+ .m b { color:var(--ink); font-weight:600; flex:none; }
37
+ .m .t { overflow:hidden; text-overflow:ellipsis; font-family:var(--serif); font-size:13px; }
38
+ .p .st { width:7px; height:7px; border-radius:50%; background:var(--ink-3); flex:none; }
39
+ .p.run .st { background:var(--str); }
40
+ .p .nm { font-weight:600; color:var(--ink); }
41
+ .p .cm { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex:1; }
42
+ .p .port { color:var(--amber); font-weight:600; text-decoration:none; flex:none; }
43
+ .p .port:hover { text-decoration:underline; text-underline-offset:.18em; }
44
+ .p button { padding:1px 7px; font-size:10px; }
45
+ .none { color:var(--ink-3); cursor:default; }
46
+ .none:hover { color:var(--ink-3); }
47
+
48
+ /* filas de tareas programadas y aprobaciones */
49
+ .p.sched { flex-wrap:wrap; }
50
+ .p.sched .st.on { background:var(--accent); }
51
+ .p.sched .st.busy { background:var(--amber); animation: pulse 1s ease-in-out infinite; }
52
+ .p.sched .st.bad { background:var(--rubric); }
53
+ .p.sched .sub { flex-basis:100%; color:var(--ink-3); font-size:10.5px; padding-left:15px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
54
+ .p.sched .act { margin-left:auto; display:inline-flex; gap:2px; visibility:hidden; }
55
+ .p.sched:hover .act, .p.sched .act.ask { visibility:visible; }
56
+ .p.sched .act span { color:var(--ink-3); font-size:11px; padding:0 4px; cursor:pointer; }
57
+ .p.sched .act span:hover { color:var(--accent); }
58
+ .p.sched .act span.rm:hover { color:var(--rubric); }
59
+ .p.appr { flex-wrap:wrap; cursor:default; }
60
+ .p.appr .msg { flex-basis:100%; color:var(--ink); font-size:11.5px; white-space:pre-wrap; padding-left:15px; }
61
+ .p.appr .why { flex-basis:100%; color:var(--rubric); font-size:10.5px; padding-left:15px; }
62
+ .p.appr .btns { flex-basis:100%; display:flex; gap:6px; padding:4px 0 2px 15px; }
63
+ .p.appr .btns button { padding:2px 9px; font-size:11px; }
64
+ .sec .daemon { font:400 10.5px/1.5 var(--mono); color:var(--ink-3); padding:2px 0 4px; }
65
+ .sec .daemon.off { color:var(--rubric); }
66
+ @keyframes pulse { 0%,100% { opacity:1 } 50% { opacity:.35 } }
67
+
68
+ .s.more { color:var(--accent); }
69
+
70
+ /* ✕ → «¿borrar? sí · no» en línea */
71
+ .s .del { margin-left:auto; color:var(--ink-3); visibility:hidden; font-size:11px; padding:0 4px; }
72
+ .s:hover .del { visibility:visible; }
73
+ .s .del:hover { color:var(--rubric); }
74
+ .p .del { margin-left:auto; color:var(--ink-3); visibility:hidden; font-size:11px; padding:0 4px; cursor:pointer; }
75
+ .p:hover .del { visibility:visible; }
76
+ .p .del:hover { color:var(--rubric); }
77
+ .del.ask, .s:hover .del.ask { visibility:visible; color:var(--ink-2); font:400 11px/1.4 var(--mono); white-space:nowrap; }
78
+ .del.ask .yes { color:var(--rubric); cursor:pointer; font-weight:600; }
79
+ .del.ask .no { color:var(--ink-2); cursor:pointer; }
80
+ .del.ask .yes:hover, .del.ask .no:hover { text-decoration:underline; text-underline-offset:.18em; }
@@ -0,0 +1,57 @@
1
+ /* tokens: fuentes, paleta (dark/light), base y botones — lo que todo lo demás asume */
2
+ /* Misma dirección que docs.synsema.com: tinta sobre papel, una superfamilia (IBM Plex) en dos
3
+ voces — la SERIF para lo que se lee (mensajes, hero), la MONO para estructura y maquinaria
4
+ (header, sidebar, pasos, código, controles). El color se raciona: azul = link / dónde estás,
5
+ rubric rojo = peligro y permisos (la única cosa que vale la pena ver desde lejos). */
6
+ @font-face{font-family:"Plex Serif";font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-serif-400-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
7
+ @font-face{font-family:"Plex Serif";font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-serif-400-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
8
+ @font-face{font-family:"Plex Serif";font-style:italic;font-weight:400;font-display:swap;src:url(/fonts/plex-serif-400i-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
9
+ @font-face{font-family:"Plex Serif";font-style:italic;font-weight:400;font-display:swap;src:url(/fonts/plex-serif-400i-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
10
+ @font-face{font-family:"Plex Serif";font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-serif-600-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
11
+ @font-face{font-family:"Plex Serif";font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-serif-600-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
12
+ @font-face{font-family:"Plex Mono";font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
13
+ @font-face{font-family:"Plex Mono";font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/plex-mono-400-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
14
+ @font-face{font-family:"Plex Mono";font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-mono-600-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
15
+ @font-face{font-family:"Plex Mono";font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/plex-mono-600-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
16
+
17
+ :root, :root[data-theme=dark] {
18
+ --paper:#131412; --paper-2:#1b1c19; --paper-3:#212320;
19
+ --ink:#e9e8df; --ink-2:#9b9c90; --ink-3:#848678;
20
+ --rule:#2b2c27; --rule-2:#3c3d36;
21
+ --accent:#8fb4dc; --accent-bg:#1b2836;
22
+ --rubric:#d98670; --str:#a8bd84; --amber:#d9b26f;
23
+ --sel:#33465b; --term-blue:#4f86d1;
24
+ --serif:"Plex Serif",Georgia,"Times New Roman",serif;
25
+ --mono:"Plex Mono",ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace;
26
+ --r:3px; --side:280px;
27
+ }
28
+ :root[data-theme=light] {
29
+ --paper:#fcfcfa; --paper-2:#f4f3ee; --paper-3:#ecebe3;
30
+ --ink:#1a1b18; --ink-2:#56584f; --ink-3:#6a6c61;
31
+ --rule:#e4e3da; --rule-2:#cfcec2;
32
+ --accent:#21578c; --accent-bg:#e9eef4;
33
+ --rubric:#99372a; --str:#4a6b3f; --amber:#8a6a1f;
34
+ --sel:#cfe0f0; --term-blue:#21578c;
35
+ }
36
+
37
+ * { box-sizing:border-box; }
38
+ html, body { height:100%; }
39
+ body { margin:0; background:var(--paper); color:var(--ink); font:400 14.5px/1.6 var(--serif); -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; }
40
+ ::selection { background:var(--sel); }
41
+ :focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:1px; }
42
+ button, select, textarea { font-family:inherit; }
43
+ .spacer { flex:1; }
44
+
45
+ /* botones: el primario es tinta sobre papel, el secundario solo borde */
46
+ button { font:600 10.5px/1 var(--mono); text-transform:uppercase; letter-spacing:.09em; color:var(--ink-2); background:none; border:1px solid var(--rule-2); border-radius:2px; padding:7px 12px; cursor:pointer; }
47
+ button:hover { color:var(--ink); border-color:var(--ink-3); }
48
+ button.primary { color:var(--paper); background:var(--ink); border-color:var(--ink); }
49
+ button.primary:hover { opacity:.85; color:var(--paper); }
50
+ button:disabled { opacity:.45; cursor:default; }
51
+
52
+ /* barras de scroll finas y del color del tema (las nativas de Windows son gruesas y grises) */
53
+ * { scrollbar-width:thin; scrollbar-color:var(--rule-2) transparent; }
54
+ *::-webkit-scrollbar { width:7px; height:7px; }
55
+ *::-webkit-scrollbar-track { background:transparent; }
56
+ *::-webkit-scrollbar-thumb { background:var(--rule-2); border-radius:4px; }
57
+ *::-webkit-scrollbar-thumb:hover { background:var(--ink-3); }