eklavya 1.9.2 → 1.9.3

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.
@@ -4,95 +4,126 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Eklavya — learning progress</title>
7
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24' rx='5' fill='%23049D66'/%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 5a11 11 0 0 1 0 14'/%3E%3Cpath d='M6 12h12'/%3E%3Cpath d='M14 9l3 3-3 3'/%3E%3C/g%3E%3C/svg%3E">
7
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24' fill='%230E6E66'/%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 5a11 11 0 0 1 0 14'/%3E%3Cpath d='M6 12h12'/%3E%3Cpath d='M14 9l3 3-3 3'/%3E%3C/g%3E%3C/svg%3E">
8
+ <script>
9
+ /* Ground selection, shared with the site: same localStorage key, same default.
10
+ Runs before the stylesheet so the page never paints one ground then swaps.
11
+ Ink is the default and an absent choice stays ink — deliberately not the
12
+ reader's OS setting, because this is a terminal tool. */
13
+ (function () {
14
+ window.eklavyaGround = {
15
+ read: function () {
16
+ try { return localStorage.getItem('eklavya-ground') === 'paper' ? 'paper' : 'ink'; }
17
+ catch (e) { return 'ink'; }
18
+ },
19
+ apply: function (mode) {
20
+ document.documentElement.setAttribute('data-mode', mode);
21
+ document.querySelectorAll('[data-ground]').forEach(function (b) {
22
+ b.setAttribute('aria-pressed', String(b.dataset.ground === mode));
23
+ });
24
+ return mode;
25
+ },
26
+ set: function (mode) {
27
+ try { localStorage.setItem('eklavya-ground', mode); } catch (e) {}
28
+ this.apply(mode);
29
+ }
30
+ };
31
+ window.eklavyaGround.apply(window.eklavyaGround.read());
32
+ })();
33
+ </script>
8
34
  <link rel="stylesheet" href="/tokens.css">
9
35
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
36
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
37
+ <link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
12
38
  <style>
13
39
  *, *::before, *::after { box-sizing: border-box; }
14
- body { margin:0; font-family:var(--font-sans); background:var(--bg-subtle); color:var(--fg);
15
- font-size:var(--text-base); line-height:var(--lh-base); }
40
+ body { margin:0; font-family:var(--font-body); background:var(--bg); color:var(--ink);
41
+ font-size:14.5px; line-height:1.65;
42
+ background-image:
43
+ linear-gradient(var(--grid) 1px, transparent 1px),
44
+ linear-gradient(90deg, var(--grid) 1px, transparent 1px);
45
+ background-size:72px 72px; }
46
+ ::selection { background:var(--spot); color:var(--spot-ink); }
16
47
  .wrap { max-width:1140px; margin:0 auto; padding:0 var(--space-8); }
17
48
  code, .mono { font-family:var(--font-mono); font-size:var(--text-sm); }
18
49
 
19
50
  /* ---------- header ---------- */
20
- header { background:var(--neutral-900); color:var(--on-dark); padding:var(--space-8) 0 var(--space-10); }
51
+ header { border-bottom:1px solid var(--line-2); padding:var(--space-8) 0 var(--space-10); }
21
52
  .bar { display:flex; align-items:center; gap:var(--space-4); flex-wrap:wrap; }
22
- .mark { width:36px; height:36px; border-radius:var(--radius-md); background:var(--brand);
53
+ .mark { width:34px; height:34px; background:var(--spot); color:var(--spot-ink);
23
54
  display:grid; place-items:center; flex:none; }
24
- h1 { font-size:var(--text-xl); font-weight:var(--weight-bold); letter-spacing:-.02em; margin:0; }
25
- .sub { color:var(--on-dark-muted); font-size:var(--text-sm); margin:2px 0 0; }
55
+ h1 { font-family:var(--font-disp); font-size:26px; font-weight:var(--weight-extra);
56
+ letter-spacing:var(--tracking-tight); margin:0; }
57
+ .sub { color:var(--dim); font-size:var(--text-sm); margin:2px 0 0; }
26
58
  .spacer { flex:1 1 auto; }
27
- select { font:inherit; font-size:var(--text-sm); background:var(--neutral-800); color:var(--on-dark);
28
- border:1px solid var(--neutral-700); border-radius:var(--radius-md);
59
+ select { font:inherit; font-size:var(--text-sm); background:var(--panel); color:var(--ink);
60
+ border:1px solid var(--line-2); border-radius:0;
29
61
  padding:var(--space-2) var(--space-3); }
30
62
  select:focus-visible { outline:none; box-shadow:var(--ring); }
31
63
 
32
64
  /* ---------- stat tiles ---------- */
33
65
  .tiles { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-4); margin-top:var(--space-6); }
34
- .tile { background:var(--neutral-800); border:1px solid var(--neutral-700); border-radius:var(--radius-lg);
66
+ .tile { background:var(--panel); border:1px solid var(--line-2); border-radius:0;
35
67
  padding:var(--space-5); }
36
68
  .tile .k { font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
37
- text-transform:uppercase; color:var(--on-dark-muted); }
69
+ text-transform:uppercase; color:var(--dim); }
38
70
  .tile .v { font-size:var(--text-3xl); font-weight:var(--weight-extra,800); letter-spacing:-.025em;
39
71
  line-height:1.1; margin-top:var(--space-2); }
40
- .tile .n { font-size:var(--text-sm); color:var(--on-dark-muted); margin-top:var(--space-1); }
41
- .good { color:var(--green-300); }
72
+ .tile .n { font-size:var(--text-sm); color:var(--dim); margin-top:var(--space-1); }
73
+ .good { color:var(--spot); }
42
74
 
43
75
  /* ---------- cards ---------- */
44
76
  main { padding:var(--space-10) 0 var(--space-20); }
45
- section { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg);
77
+ section { background:var(--panel); border:1px solid var(--line); border-radius:0;
46
78
  padding:var(--space-6); margin-bottom:var(--space-6); }
47
79
  h2 { font-size:var(--text-md); font-weight:var(--weight-bold); letter-spacing:-.01em; margin:0; }
48
- .hint { color:var(--fg-subtle); font-size:var(--text-sm); margin:var(--space-1) 0 var(--space-5); }
80
+ .hint { color:var(--faint); font-size:var(--text-sm); margin:var(--space-1) 0 var(--space-5); }
49
81
  .grid2 { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-6); }
50
82
  .grid2 > section { margin:0; }
51
83
 
52
84
  /* ---------- tables ---------- */
53
85
  table { width:100%; border-collapse:collapse; font-size:var(--text-sm); }
54
86
  th { text-align:left; font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
55
- text-transform:uppercase; color:var(--fg-subtle); padding:0 var(--space-3) var(--space-2) 0;
56
- border-bottom:1px solid var(--border); white-space:nowrap; }
57
- td { padding:var(--space-3) var(--space-3) var(--space-3) 0; border-bottom:1px solid var(--border);
87
+ text-transform:uppercase; color:var(--faint); padding:0 var(--space-3) var(--space-2) 0;
88
+ border-bottom:1px solid var(--line); white-space:nowrap; }
89
+ td { padding:var(--space-3) var(--space-3) var(--space-3) 0; border-bottom:1px solid var(--line);
58
90
  vertical-align:top; }
59
91
  tr:last-child td { border-bottom:none; }
60
92
  .num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
61
93
  .scroll { overflow-x:auto; }
62
94
 
63
95
  /* ---------- meters (sequential, one hue) ---------- */
64
- .meter { height:8px; border-radius:var(--radius-pill); background:var(--bg-sunken); overflow:hidden;
96
+ .meter { height:8px; border-radius:var(--radius-pill); background:var(--mass); overflow:hidden;
65
97
  min-width:80px; }
66
- .meter > i { display:block; height:100%; background:var(--brand); border-radius:var(--radius-pill); }
98
+ .meter > i { display:block; height:100%; background:var(--spot); border-radius:var(--radius-pill); }
67
99
  .meter.warn > i { background:var(--warning); }
68
100
 
69
101
  /* ---------- chart ---------- */
70
- .legend { display:flex; gap:var(--space-5); font-size:var(--text-sm); color:var(--fg-muted);
102
+ .legend { display:flex; gap:var(--space-5); font-size:var(--text-sm); color:var(--dim);
71
103
  margin-bottom:var(--space-4); flex-wrap:wrap; }
72
104
  .legend b { display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:var(--space-2); }
73
105
  .chart { position:relative; }
74
106
  .chart svg { display:block; width:100%; height:200px; overflow:visible; }
75
- .gridline { stroke:var(--border); stroke-width:1; }
76
- .axis { font-family:var(--font-mono); font-size:10px; fill:var(--fg-faint); }
107
+ .gridline { stroke:var(--line); stroke-width:1; }
108
+ .axis { font-family:var(--font-mono); font-size:10px; fill:var(--faint-2); }
77
109
  .hit { fill:transparent; cursor:pointer; }
78
110
  .hit:hover + .col, .hit:focus-visible + .col { opacity:.75; }
79
111
  .tip { position:absolute; pointer-events:none; opacity:0; transform:translate(-50%,-100%);
80
- background:var(--neutral-900); color:var(--on-dark); border-radius:var(--radius-md);
81
- padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap;
82
- box-shadow:var(--shadow-md); transition:opacity var(--duration-fast) var(--ease); z-index:2; }
112
+ background:var(--panel); color:var(--ink); border-radius:0;
113
+ padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap; transition:opacity var(--duration-fast) var(--ease); z-index:2; }
83
114
  .tip.on { opacity:1; }
84
115
  .tip .r { display:flex; justify-content:space-between; gap:var(--space-4); }
85
116
 
86
117
  /* ---------- pills & misc ---------- */
87
118
  .pill { display:inline-block; font-family:var(--font-mono); font-size:var(--text-xs);
88
- padding:2px 8px; border-radius:var(--radius-pill); background:var(--bg-sunken);
89
- color:var(--fg-muted); white-space:nowrap; }
90
- .pill.due { background:var(--warning-bg); color:#8a5600; }
91
- .pill.ok { background:var(--brand-subtle); color:var(--green-700); }
92
- .ctx { color:var(--fg); }
93
- .slug { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--fg-subtle); }
94
- .empty { color:var(--fg-subtle); font-size:var(--text-sm); }
95
- footer { color:var(--fg-subtle); font-size:var(--text-sm); text-align:center; padding-bottom:var(--space-10); }
119
+ padding:2px 8px; border-radius:var(--radius-pill); background:var(--mass);
120
+ color:var(--dim); white-space:nowrap; }
121
+ .pill.due { background:var(--mass); color:var(--warning); }
122
+ .pill.ok { background:var(--spot-soft); color:var(--spot); }
123
+ .ctx { color:var(--ink); }
124
+ .slug { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--faint); }
125
+ .empty { color:var(--faint); font-size:var(--text-sm); }
126
+ footer { color:var(--faint); font-size:var(--text-sm); text-align:center; padding-bottom:var(--space-10); }
96
127
 
97
128
  @media (max-width:900px) {
98
129
  .tiles { grid-template-columns:repeat(2,1fr); }
@@ -104,6 +135,17 @@
104
135
  .tile .v { font-size:var(--text-2xl); }
105
136
  }
106
137
  @media (prefers-reduced-motion:reduce) { * { transition:none !important; animation:none !important; } }
138
+
139
+ /* ---------- the ground toggle ---------- */
140
+ .ground { display:flex; border:1px solid var(--line-2); flex:none; }
141
+ .ground button {
142
+ font-family:var(--font-mono); font-size:11px; letter-spacing:.12em;
143
+ text-transform:uppercase; background:none; border:0; color:var(--faint);
144
+ padding:6px 11px; cursor:pointer; line-height:1.4;
145
+ transition:background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
146
+ }
147
+ .ground button:hover { color:var(--ink); }
148
+ .ground button[aria-pressed="true"] { background:var(--ink); color:var(--bg); }
107
149
  </style>
108
150
  </head>
109
151
  <body>
@@ -111,7 +153,7 @@
111
153
  <div class="wrap">
112
154
  <div class="bar">
113
155
  <div class="mark" aria-hidden="true">
114
- <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="1.8"
156
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
115
157
  stroke-linecap="round" stroke-linejoin="round">
116
158
  <path d="M5 3a13 13 0 0 1 0 18"/><path d="M5 3l14 9L5 21"/><path d="M3 12h18"/><path d="M15 8l4 4-4 4"/>
117
159
  </svg>
@@ -121,6 +163,10 @@
121
163
  <p class="sub" id="sub">Loading…</p>
122
164
  </div>
123
165
  <div class="spacer"></div>
166
+ <div class="ground" role="group" aria-label="Colour ground">
167
+ <button type="button" data-ground="ink" aria-pressed="true">ink</button>
168
+ <button type="button" data-ground="paper" aria-pressed="false">paper</button>
169
+ </div>
124
170
  <label class="sub" for="proj">Project</label>
125
171
  <select id="proj"><option value="*">All projects</option></select>
126
172
  </div>
@@ -133,9 +179,9 @@
133
179
  <h2>Answers over the last 30 days</h2>
134
180
  <p class="hint" id="chart-hint">Right, missed and skipped, per day.</p>
135
181
  <div class="legend">
136
- <span><b style="background:var(--green-600)"></b>Right</span>
182
+ <span><b style="background:var(--spot)"></b>Right</span>
137
183
  <span><b style="background:var(--warning)"></b>Missed</span>
138
- <span><b style="background:var(--neutral-400)"></b>Skipped</span>
184
+ <span><b style="background:var(--faint)"></b>Skipped</span>
139
185
  </div>
140
186
  <div class="chart"><div class="tip" id="tip"></div><svg id="chart" role="img"
141
187
  aria-label="Daily answers, split into right, missed and skipped"></svg></div>
@@ -262,11 +308,11 @@ function renderChart() {
262
308
  }
263
309
  // Stack order is fixed: right at the base, then missed, then skipped on top.
264
310
  // Segment colour never depends on rank, only on which measure it is.
265
- const SEGMENTS = [['passed', 'var(--green-600)'], ['missed', 'var(--warning)'], ['skipped', 'var(--neutral-400)']];
311
+ const SEGMENTS = [['passed', 'var(--spot)'], ['missed', 'var(--warning)'], ['skipped', 'var(--faint)']];
266
312
  const labelEvery = Math.max(1, Math.ceil(46 / step));
267
313
  days.forEach((d, i) => {
268
314
  const x = PAD_L + i * step + (step - bw) / 2;
269
- let acc = 0, seg = '', topColor = 'var(--green-600)';
315
+ let acc = 0, seg = '', topColor = 'var(--spot)';
270
316
  for (const [key, color] of SEGMENTS) {
271
317
  if (!d[key]) continue;
272
318
  const h = (d[key] / max) * (H - PAD_B - 8);
@@ -403,5 +449,10 @@ fetch('/api/state').then((r) => r.json()).then((s) => {
403
449
  addEventListener('resize', renderChart);
404
450
  }).catch((e) => { $('sub').textContent = 'Could not read the database: ' + e.message; });
405
451
  </script>
452
+ <script>
453
+ document.querySelectorAll('[data-ground]').forEach(function (b) {
454
+ b.addEventListener('click', function () { window.eklavyaGround.set(b.dataset.ground); });
455
+ });
456
+ </script>
406
457
  </body>
407
458
  </html>
@@ -128,7 +128,7 @@
128
128
 
129
129
  --ink: #EAE7E1; /* primary text */
130
130
  --dim: #A29C93; /* secondary */
131
- --faint: #77726A; /* captions, micro-labels */
131
+ --faint: #8B857B; /* captions, micro-labels — 4.89:1 on ink */
132
132
  --faint-2: #565249; /* disabled, placeholder */
133
133
 
134
134
  --line: #26262a; /* hairline */
@@ -153,7 +153,7 @@
153
153
 
154
154
  --ink: #16150f;
155
155
  --dim: #57534a;
156
- --faint: #8a8578;
156
+ --faint: #6E695E; /* 4.67:1 on paper */
157
157
  --faint-2: #a09a8c;
158
158
 
159
159
  --line: #e3dfd4;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eklavya",
3
3
  "displayName": "Eklavya",
4
- "version": "1.9.2",
4
+ "version": "1.9.3",
5
5
  "description": "Learn while your agent works. Turns coding-agent generation time into adaptive, Socratic learning grounded in the code being written.",
6
6
  "author": {
7
7
  "name": "Ajay Kumar"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eklavya",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "Learn while your agent works — local knowledge graph, spaced repetition, and quiz gating for agent-assisted development.",
5
5
  "license": "MIT",
6
6
  "repository": {