estela 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.
Files changed (186) hide show
  1. package/README.md +138 -0
  2. package/dist/billing/amortize.d.ts +44 -0
  3. package/dist/billing/amortize.d.ts.map +1 -0
  4. package/dist/billing/amortize.js +83 -0
  5. package/dist/billing/amortize.js.map +1 -0
  6. package/dist/billing/amortize.test.d.ts +2 -0
  7. package/dist/billing/amortize.test.d.ts.map +1 -0
  8. package/dist/billing/amortize.test.js +121 -0
  9. package/dist/billing/amortize.test.js.map +1 -0
  10. package/dist/billing/format.test.d.ts +2 -0
  11. package/dist/billing/format.test.d.ts.map +1 -0
  12. package/dist/billing/format.test.js +110 -0
  13. package/dist/billing/format.test.js.map +1 -0
  14. package/dist/billing/invoice.d.ts +52 -0
  15. package/dist/billing/invoice.d.ts.map +1 -0
  16. package/dist/billing/invoice.js +148 -0
  17. package/dist/billing/invoice.js.map +1 -0
  18. package/dist/billing/invoice.test.d.ts +2 -0
  19. package/dist/billing/invoice.test.d.ts.map +1 -0
  20. package/dist/billing/invoice.test.js +200 -0
  21. package/dist/billing/invoice.test.js.map +1 -0
  22. package/dist/billing/sessionize.d.ts +104 -0
  23. package/dist/billing/sessionize.d.ts.map +1 -0
  24. package/dist/billing/sessionize.js +0 -0
  25. package/dist/billing/sessionize.js.map +1 -0
  26. package/dist/billing/sessionize.test.d.ts +2 -0
  27. package/dist/billing/sessionize.test.d.ts.map +1 -0
  28. package/dist/billing/sessionize.test.js +67 -0
  29. package/dist/billing/sessionize.test.js.map +1 -0
  30. package/dist/cli.d.ts +4 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +1091 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/cloud/auth.d.ts +4 -0
  35. package/dist/cloud/auth.d.ts.map +1 -0
  36. package/dist/cloud/auth.js +98 -0
  37. package/dist/cloud/auth.js.map +1 -0
  38. package/dist/cloud/client.d.ts +12 -0
  39. package/dist/cloud/client.d.ts.map +1 -0
  40. package/dist/cloud/client.js +34 -0
  41. package/dist/cloud/client.js.map +1 -0
  42. package/dist/db/schema.d.ts +11 -0
  43. package/dist/db/schema.d.ts.map +1 -0
  44. package/dist/db/schema.js +424 -0
  45. package/dist/db/schema.js.map +1 -0
  46. package/dist/db/schema.test.d.ts +2 -0
  47. package/dist/db/schema.test.d.ts.map +1 -0
  48. package/dist/db/schema.test.js +335 -0
  49. package/dist/db/schema.test.js.map +1 -0
  50. package/dist/db/store.d.ts +113 -0
  51. package/dist/db/store.d.ts.map +1 -0
  52. package/dist/db/store.js +550 -0
  53. package/dist/db/store.js.map +1 -0
  54. package/dist/doctor.d.ts +24 -0
  55. package/dist/doctor.d.ts.map +1 -0
  56. package/dist/doctor.js +229 -0
  57. package/dist/doctor.js.map +1 -0
  58. package/dist/export/csv.d.ts +9 -0
  59. package/dist/export/csv.d.ts.map +1 -0
  60. package/dist/export/csv.js +81 -0
  61. package/dist/export/csv.js.map +1 -0
  62. package/dist/export/invoice-pdf.d.ts +21 -0
  63. package/dist/export/invoice-pdf.d.ts.map +1 -0
  64. package/dist/export/invoice-pdf.js +135 -0
  65. package/dist/export/invoice-pdf.js.map +1 -0
  66. package/dist/export/panel.d.ts +78 -0
  67. package/dist/export/panel.d.ts.map +1 -0
  68. package/dist/export/panel.js +693 -0
  69. package/dist/export/panel.js.map +1 -0
  70. package/dist/export/panel.test.d.ts +2 -0
  71. package/dist/export/panel.test.d.ts.map +1 -0
  72. package/dist/export/panel.test.js +273 -0
  73. package/dist/export/panel.test.js.map +1 -0
  74. package/dist/export/pdf.d.ts +32 -0
  75. package/dist/export/pdf.d.ts.map +1 -0
  76. package/dist/export/pdf.js +229 -0
  77. package/dist/export/pdf.js.map +1 -0
  78. package/dist/export/pdf.test.d.ts +2 -0
  79. package/dist/export/pdf.test.d.ts.map +1 -0
  80. package/dist/export/pdf.test.js +151 -0
  81. package/dist/export/pdf.test.js.map +1 -0
  82. package/dist/export/share.d.ts +42 -0
  83. package/dist/export/share.d.ts.map +1 -0
  84. package/dist/export/share.js +181 -0
  85. package/dist/export/share.js.map +1 -0
  86. package/dist/export/share.test.d.ts +2 -0
  87. package/dist/export/share.test.d.ts.map +1 -0
  88. package/dist/export/share.test.js +116 -0
  89. package/dist/export/share.test.js.map +1 -0
  90. package/dist/metrics/index.d.ts +101 -0
  91. package/dist/metrics/index.d.ts.map +1 -0
  92. package/dist/metrics/index.js +221 -0
  93. package/dist/metrics/index.js.map +1 -0
  94. package/dist/metrics/metrics.test.d.ts +2 -0
  95. package/dist/metrics/metrics.test.d.ts.map +1 -0
  96. package/dist/metrics/metrics.test.js +162 -0
  97. package/dist/metrics/metrics.test.js.map +1 -0
  98. package/dist/metrics/people.d.ts +46 -0
  99. package/dist/metrics/people.d.ts.map +1 -0
  100. package/dist/metrics/people.js +126 -0
  101. package/dist/metrics/people.js.map +1 -0
  102. package/dist/metrics/people.test.d.ts +2 -0
  103. package/dist/metrics/people.test.d.ts.map +1 -0
  104. package/dist/metrics/people.test.js +84 -0
  105. package/dist/metrics/people.test.js.map +1 -0
  106. package/dist/metrics/team.d.ts +41 -0
  107. package/dist/metrics/team.d.ts.map +1 -0
  108. package/dist/metrics/team.js +0 -0
  109. package/dist/metrics/team.js.map +1 -0
  110. package/dist/metrics/team.test.d.ts +2 -0
  111. package/dist/metrics/team.test.d.ts.map +1 -0
  112. package/dist/metrics/team.test.js +90 -0
  113. package/dist/metrics/team.test.js.map +1 -0
  114. package/dist/pricing/catalog.d.ts +39 -0
  115. package/dist/pricing/catalog.d.ts.map +1 -0
  116. package/dist/pricing/catalog.js +59 -0
  117. package/dist/pricing/catalog.js.map +1 -0
  118. package/dist/pricing/cost.d.ts +25 -0
  119. package/dist/pricing/cost.d.ts.map +1 -0
  120. package/dist/pricing/cost.js +50 -0
  121. package/dist/pricing/cost.js.map +1 -0
  122. package/dist/pricing/cost.test.d.ts +2 -0
  123. package/dist/pricing/cost.test.d.ts.map +1 -0
  124. package/dist/pricing/cost.test.js +74 -0
  125. package/dist/pricing/cost.test.js.map +1 -0
  126. package/dist/server.d.ts +15 -0
  127. package/dist/server.d.ts.map +1 -0
  128. package/dist/server.js +1141 -0
  129. package/dist/server.js.map +1 -0
  130. package/dist/setup.d.ts +70 -0
  131. package/dist/setup.d.ts.map +1 -0
  132. package/dist/setup.js +223 -0
  133. package/dist/setup.js.map +1 -0
  134. package/dist/setup.test.d.ts +2 -0
  135. package/dist/setup.test.d.ts.map +1 -0
  136. package/dist/setup.test.js +131 -0
  137. package/dist/setup.test.js.map +1 -0
  138. package/dist/watchers/claude.d.ts +34 -0
  139. package/dist/watchers/claude.d.ts.map +1 -0
  140. package/dist/watchers/claude.js +235 -0
  141. package/dist/watchers/claude.js.map +1 -0
  142. package/dist/watchers/claude.test.d.ts +2 -0
  143. package/dist/watchers/claude.test.d.ts.map +1 -0
  144. package/dist/watchers/claude.test.js +180 -0
  145. package/dist/watchers/claude.test.js.map +1 -0
  146. package/dist/watchers/git.d.ts +42 -0
  147. package/dist/watchers/git.d.ts.map +1 -0
  148. package/dist/watchers/git.js +218 -0
  149. package/dist/watchers/git.js.map +1 -0
  150. package/dist/watchers/git.test.d.ts +2 -0
  151. package/dist/watchers/git.test.d.ts.map +1 -0
  152. package/dist/watchers/git.test.js +73 -0
  153. package/dist/watchers/git.test.js.map +1 -0
  154. package/dist/watchers/identity.d.ts +34 -0
  155. package/dist/watchers/identity.d.ts.map +1 -0
  156. package/dist/watchers/identity.js +85 -0
  157. package/dist/watchers/identity.js.map +1 -0
  158. package/dist/watchers/identity.test.d.ts +2 -0
  159. package/dist/watchers/identity.test.d.ts.map +1 -0
  160. package/dist/watchers/identity.test.js +48 -0
  161. package/dist/watchers/identity.test.js.map +1 -0
  162. package/dist/web-ui.test.d.ts +2 -0
  163. package/dist/web-ui.test.d.ts.map +1 -0
  164. package/dist/web-ui.test.js +312 -0
  165. package/dist/web-ui.test.js.map +1 -0
  166. package/node_modules/@estela/shared/dist/index.d.ts +3 -0
  167. package/node_modules/@estela/shared/dist/index.d.ts.map +1 -0
  168. package/node_modules/@estela/shared/dist/index.js +19 -0
  169. package/node_modules/@estela/shared/dist/index.js.map +1 -0
  170. package/node_modules/@estela/shared/dist/money.d.ts +71 -0
  171. package/node_modules/@estela/shared/dist/money.d.ts.map +1 -0
  172. package/node_modules/@estela/shared/dist/money.js +171 -0
  173. package/node_modules/@estela/shared/dist/money.js.map +1 -0
  174. package/node_modules/@estela/shared/dist/types.d.ts +365 -0
  175. package/node_modules/@estela/shared/dist/types.d.ts.map +1 -0
  176. package/node_modules/@estela/shared/dist/types.js +24 -0
  177. package/node_modules/@estela/shared/dist/types.js.map +1 -0
  178. package/node_modules/@estela/shared/package.json +5 -0
  179. package/package.json +41 -0
  180. package/web/app.css +749 -0
  181. package/web/app.js +1257 -0
  182. package/web/apple-touch-icon.png +0 -0
  183. package/web/favicon.png +0 -0
  184. package/web/index.html +132 -0
  185. package/web/lib.js +94 -0
  186. package/web/logo-mark.png +0 -0
package/web/app.css ADDED
@@ -0,0 +1,749 @@
1
+ /* Estela — hoja de estilos del dashboard local.
2
+ Una columna, mucho aire, un número grande. El detalle solo cuando se pide. */
3
+
4
+ :root {
5
+ --paper: #F4F5F3;
6
+ --card: #FFFFFF;
7
+ --card-2: #EDEEEA;
8
+ --line: #DFE1DA;
9
+ --line-2: #C7CABF;
10
+ --ink: #191D1B;
11
+ --ink-2: #545C57;
12
+ --ink-3: #838C86;
13
+ --jade: #0E7C6B;
14
+ --jade-2: #0A5F52;
15
+ --jade-bg: #E2EFEB;
16
+ --amber: #96600E;
17
+ --amber-bg: #F5E9D3;
18
+ --danger: #A93C2A;
19
+ /* Texto sobre fondo jade. Es un token y no un @media suelto: cuando el
20
+ color del texto y el de su fondo viven en sitios distintos, acaban
21
+ desincronizados y el botón queda ilegible en uno de los dos temas. */
22
+ --on-jade: #FFFFFF;
23
+ --radius: 12px;
24
+ --shadow: 0 1px 2px rgba(25,29,27,.05), 0 10px 28px -18px rgba(25,29,27,.30);
25
+ }
26
+
27
+ @media (prefers-color-scheme: dark) {
28
+ :root {
29
+ --paper: #0E1211;
30
+ --card: #171B19;
31
+ --card-2: #1F2523;
32
+ --line: #2A322F;
33
+ --line-2: #3D4844;
34
+ --ink: #E9EEEB;
35
+ --ink-2: #A6B1AB;
36
+ --ink-3: #78837D;
37
+ --jade: #45C0A7;
38
+ --jade-2: #6BD6C0;
39
+ --jade-bg: #10322C;
40
+ --amber: #DEAA5C;
41
+ --amber-bg: #342811;
42
+ --danger: #E88770;
43
+ --on-jade: #08201C;
44
+ --shadow: 0 1px 2px rgba(0,0,0,.4), 0 10px 28px -18px rgba(0,0,0,.7);
45
+ }
46
+ }
47
+
48
+ * { box-sizing: border-box; }
49
+
50
+ /* El `[hidden] { display: none }` del navegador es una regla de user-agent, y
51
+ cualquier `display` declarado por nosotros la gana. Como .hero, .approve y
52
+ .addform son `display: flex`, el atributo `hidden` no hacía absolutamente
53
+ nada: el formulario salía siempre abierto y el resumen de un día vacío
54
+ seguía enseñando las cifras del día anterior. */
55
+ [hidden] { display: none !important; }
56
+
57
+ body {
58
+ margin: 0;
59
+ background: var(--paper);
60
+ color: var(--ink);
61
+ font: 16px/1.55 ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
62
+ -webkit-font-smoothing: antialiased;
63
+ }
64
+
65
+ h1 { margin: 0; font-size: 1.5rem; font-weight: 650; letter-spacing: -.02em; }
66
+ p { margin: 0; }
67
+ button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
68
+ :focus-visible { outline: 2px solid var(--jade); outline-offset: 3px; border-radius: 6px; }
69
+
70
+ .num { font-variant-numeric: tabular-nums; }
71
+ .mono {
72
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
73
+ font-variant-numeric: tabular-nums;
74
+ }
75
+
76
+ /* ── Cabecera ───────────────────────────────────────────────────────── */
77
+
78
+ .top {
79
+ display: flex; align-items: center; gap: 28px;
80
+ padding: 18px 24px;
81
+ border-bottom: 1px solid var(--line);
82
+ background: var(--card);
83
+ }
84
+
85
+ .brand {
86
+ display: flex; align-items: center; gap: 9px;
87
+ font-weight: 650; letter-spacing: -.015em;
88
+ }
89
+ .mark {
90
+ width: 22px; height: 22px; flex: none;
91
+ object-fit: contain; display: block;
92
+ }
93
+
94
+ .tabs { display: flex; gap: 4px; }
95
+ .tab {
96
+ padding: 6px 14px; border-radius: 999px;
97
+ color: var(--ink-2); font-size: .95rem; font-weight: 500;
98
+ }
99
+ .tab:hover { background: var(--card-2); color: var(--ink); }
100
+ .tab.is-on { background: var(--jade-bg); color: var(--jade-2); font-weight: 600; }
101
+
102
+ main { max-width: 720px; margin: 0 auto; padding: 40px 24px 80px; }
103
+
104
+ /* Mi día y los informes se leen como un documento, y 720px es el ancho en que
105
+ un texto se lee cómodo. La vista de equipo no es un texto: son tablas que
106
+ solo sirven si sus columnas caben sin cortarse, así que ensancha. */
107
+ main.wide { max-width: 1180px; }
108
+ .view { display: none; }
109
+ .view.is-on { display: block; }
110
+
111
+ /* ── Navegación por días ────────────────────────────────────────────── */
112
+
113
+ .daynav { display: flex; align-items: center; gap: 16px; margin-bottom: 32px; }
114
+ .daynav-label { flex: 1; text-align: center; }
115
+ .arrow {
116
+ width: 38px; height: 38px; border-radius: 50%; flex: none;
117
+ border: 1px solid var(--line); color: var(--ink-2); font-size: 1rem;
118
+ display: grid; place-items: center; background: var(--card);
119
+ }
120
+ .arrow:hover:not(:disabled) { border-color: var(--line-2); color: var(--ink); }
121
+ .arrow:disabled { opacity: .3; cursor: default; }
122
+
123
+ .today-link {
124
+ font-size: .82rem; color: var(--jade-2); font-weight: 600; margin-top: 3px;
125
+ }
126
+ .today-link:hover { text-decoration: underline; }
127
+
128
+ /* ── El número grande ───────────────────────────────────────────────── */
129
+
130
+ .hero {
131
+ display: flex; gap: 12px; margin-bottom: 28px;
132
+ }
133
+ .hero-main {
134
+ flex: 1; background: var(--card); border: 1px solid var(--line);
135
+ border-radius: var(--radius); padding: 22px 24px;
136
+ }
137
+ .hero-money { background: var(--jade-bg); border-color: transparent; }
138
+ .hero-value {
139
+ font-size: 2.35rem; font-weight: 640; letter-spacing: -.035em; line-height: 1.05;
140
+ font-variant-numeric: tabular-nums;
141
+ }
142
+ .hero-money .hero-value { color: var(--jade-2); }
143
+ .hero-label { font-size: .88rem; color: var(--ink-3); margin-top: 5px; }
144
+ .hero-money .hero-label { color: var(--jade-2); opacity: .8; }
145
+
146
+ /* ── Las filas del día ──────────────────────────────────────────────── */
147
+
148
+ .rows { display: flex; flex-direction: column; gap: 10px; }
149
+
150
+ .row {
151
+ background: var(--card); border: 1px solid var(--line);
152
+ border-radius: var(--radius); overflow: hidden;
153
+ transition: border-color .15s, box-shadow .15s;
154
+ }
155
+ .row:hover { border-color: var(--line-2); box-shadow: var(--shadow); }
156
+ .row.is-open { border-color: var(--line-2); box-shadow: var(--shadow); }
157
+ .row.not-billable { background: var(--card-2); }
158
+ .row.is-invoiced { opacity: .6; }
159
+
160
+ .row-head {
161
+ display: flex; align-items: center; gap: 16px;
162
+ padding: 16px 20px; width: 100%; text-align: left;
163
+ }
164
+
165
+ /* display:block es obligatorio: text-overflow no hace nada sobre un span
166
+ inline, y el título se comería la columna de importes. */
167
+ .row-text { flex: 1; min-width: 0; display: block; }
168
+ .row-title {
169
+ display: block;
170
+ font-size: 1.02rem; font-weight: 560; letter-spacing: -.01em;
171
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
172
+ }
173
+ .row-meta {
174
+ display: block;
175
+ font-size: .85rem; color: var(--ink-3); margin-top: 3px;
176
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
177
+ }
178
+
179
+ .row-figs { text-align: right; flex: none; display: block; }
180
+ .row-time {
181
+ display: block;
182
+ font-size: 1.02rem; font-weight: 560; font-variant-numeric: tabular-nums;
183
+ white-space: nowrap;
184
+ }
185
+ .row-money {
186
+ display: block;
187
+ font-size: .85rem; color: var(--jade-2); font-weight: 600; margin-top: 3px;
188
+ white-space: nowrap;
189
+ }
190
+ .row-money.none { color: var(--ink-3); font-weight: 400; }
191
+
192
+ .chev {
193
+ flex: none; color: var(--ink-3); font-size: .8rem;
194
+ transition: transform .18s;
195
+ }
196
+ .row.is-open .chev { transform: rotate(90deg); }
197
+
198
+ .check {
199
+ width: 20px; height: 20px; border-radius: 50%; flex: none;
200
+ border: 1.5px solid var(--line-2); display: grid; place-items: center;
201
+ color: transparent; font-size: .7rem;
202
+ }
203
+ .row.is-approved .check {
204
+ background: var(--jade); border-color: var(--jade); color: var(--on-jade);
205
+ }
206
+
207
+ /* Detalle: solo cuando se pide */
208
+ .row-body {
209
+ padding: 4px 20px 18px 56px;
210
+ display: flex; flex-direction: column; gap: 14px;
211
+ border-top: 1px solid var(--line);
212
+ margin-top: -1px; padding-top: 16px;
213
+ }
214
+ .field { display: flex; flex-direction: column; gap: 5px; }
215
+ .field label { font-size: .78rem; color: var(--ink-3); font-weight: 600; }
216
+ .field input, .field select {
217
+ border: 1px solid var(--line-2); border-radius: 8px; padding: 8px 11px;
218
+ background: var(--paper); color: var(--ink); font: inherit; font-size: .95rem;
219
+ width: 100%;
220
+ }
221
+ .field-pair { display: flex; gap: 12px; }
222
+ .field-pair .field { flex: 1; }
223
+
224
+ .commits { display: flex; flex-direction: column; gap: 5px; }
225
+ .commit { display: flex; gap: 9px; align-items: baseline; font-size: .87rem; }
226
+ .commit code {
227
+ font-family: ui-monospace, Menlo, monospace; font-size: .8rem;
228
+ color: var(--jade-2); background: var(--jade-bg);
229
+ padding: 1px 6px; border-radius: 5px; flex: none;
230
+ }
231
+ .commit span { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
232
+
233
+ .detail-line { font-size: .85rem; color: var(--ink-3); }
234
+ .detail-line b { color: var(--ink-2); font-weight: 600; }
235
+
236
+ .row-actions { display: flex; gap: 8px; flex-wrap: wrap; }
237
+ .chip {
238
+ border: 1px solid var(--line-2); border-radius: 999px; padding: 5px 13px;
239
+ font-size: .85rem; color: var(--ink-2);
240
+ }
241
+ .chip:hover { border-color: var(--ink-3); color: var(--ink); }
242
+ .chip.is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }
243
+
244
+ .kindtag {
245
+ display: inline-block; font-size: .68rem; font-weight: 700; letter-spacing: .04em;
246
+ text-transform: uppercase; padding: 2px 7px; border-radius: 5px; margin-right: 8px;
247
+ background: var(--amber-bg); color: var(--amber); vertical-align: 1px;
248
+ }
249
+
250
+ .addwrap { margin-top: 12px; }
251
+ .add-toggle {
252
+ width: 100%; padding: 13px; border-radius: var(--radius);
253
+ border: 1px dashed var(--line-2); color: var(--ink-3); font-size: .92rem;
254
+ }
255
+ .add-toggle:hover { border-color: var(--jade); color: var(--jade-2); }
256
+ .addform {
257
+ background: var(--card); border: 1px solid var(--line-2);
258
+ border-radius: var(--radius); padding: 18px 20px;
259
+ display: flex; flex-direction: column; gap: 13px;
260
+ }
261
+ .addform-hint { font-size: .85rem; color: var(--ink-3); }
262
+ .addrow { display: flex; gap: 12px; }
263
+ .addrow .field { flex: 1; }
264
+ .addform .field { display: flex; flex-direction: column; gap: 5px; }
265
+ .addform .field > span { font-size: .78rem; color: var(--ink-3); font-weight: 600; }
266
+ .addform input, .addform select {
267
+ border: 1px solid var(--line-2); border-radius: 8px; padding: 9px 11px;
268
+ background: var(--paper); color: var(--ink); font: inherit; font-size: .95rem; width: 100%;
269
+ }
270
+ .addactions { display: flex; gap: 9px; justify-content: flex-end; align-items: center; }
271
+
272
+ /* ── Aprobar ────────────────────────────────────────────────────────── */
273
+
274
+ /* En flujo normal, no pegada abajo. Un día son entre una y seis filas: la
275
+ página apenas hace scroll, así que una barra fija no gana nada y en cambio
276
+ tapa el control que estás editando justo cuando lo abres. */
277
+ .approve {
278
+ margin-top: 28px;
279
+ background: var(--card); border: 1px solid var(--line-2);
280
+ border-radius: var(--radius); padding: 16px 20px;
281
+ display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
282
+ }
283
+ .approve-jump {
284
+ font-size: .92rem; color: var(--ink-2); flex: 1; min-width: 180px;
285
+ text-align: left; text-decoration: underline; text-decoration-color: var(--line-2);
286
+ text-underline-offset: 3px;
287
+ }
288
+ .approve-jump:hover { color: var(--jade-2); text-decoration-color: var(--jade); }
289
+
290
+ /* Destello al saltar a una fila: sin esto llegas al sitio y no sabes cuál era. */
291
+ .row.is-target {
292
+ border-color: var(--jade); box-shadow: 0 0 0 3px var(--jade-bg);
293
+ }
294
+ .btn-main {
295
+ background: var(--jade); color: var(--on-jade); border-radius: 9px;
296
+ padding: 11px 22px; font-weight: 650; font-size: .97rem; flex: none;
297
+ }
298
+ .btn-main:hover { background: var(--jade-2); }
299
+ .btn-main:disabled { opacity: .45; cursor: default; }
300
+
301
+ /* ── Estados vacíos y avisos ────────────────────────────────────────── */
302
+
303
+ .empty {
304
+ text-align: center; padding: 56px 24px;
305
+ border: 1px dashed var(--line-2); border-radius: var(--radius);
306
+ }
307
+ .empty h2 { margin: 0 0 8px; font-size: 1.1rem; font-weight: 600; }
308
+ .empty p { color: var(--ink-3); font-size: .93rem; max-width: 46ch; margin: 0 auto; }
309
+ .empty code {
310
+ display: inline-block; margin-top: 14px;
311
+ font-family: ui-monospace, Menlo, monospace; font-size: .85rem;
312
+ background: var(--card-2); padding: 7px 12px; border-radius: 7px; color: var(--ink-2);
313
+ }
314
+
315
+ .warn {
316
+ background: var(--amber-bg); border: 1px solid var(--amber);
317
+ border-radius: var(--radius); padding: 13px 16px; margin-bottom: 20px;
318
+ font-size: .9rem; color: var(--amber);
319
+ }
320
+
321
+ /* ── Resumen: gestión de varios proyectos ───────────────────────────── */
322
+
323
+ .section-head {
324
+ display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap;
325
+ margin-bottom: 26px;
326
+ }
327
+ .section-head > div:first-child { flex: 1; min-width: 220px; }
328
+ .sub { color: var(--ink-3); font-size: .92rem; margin-top: 4px; max-width: 54ch; }
329
+
330
+ .periods { display: flex; gap: 4px; flex: none; }
331
+ .period {
332
+ padding: 6px 13px; border-radius: 8px; font-size: .88rem;
333
+ border: 1px solid var(--line); color: var(--ink-2); background: var(--card);
334
+ }
335
+ .period:hover { border-color: var(--line-2); color: var(--ink); }
336
+ .period.is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }
337
+
338
+ .kpis {
339
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
340
+ gap: 10px; margin-bottom: 30px;
341
+ }
342
+ .kpi {
343
+ background: var(--card); border: 1px solid var(--line);
344
+ border-radius: var(--radius); padding: 16px 18px;
345
+ }
346
+ .kpi-value {
347
+ font-size: 1.55rem; overflow-wrap: anywhere; font-weight: 640; letter-spacing: -.03em; line-height: 1.1;
348
+ font-variant-numeric: tabular-nums;
349
+ }
350
+ .kpi-label { font-size: .82rem; color: var(--ink-3); margin-top: 4px; }
351
+ .kpi-money { background: var(--jade-bg); border-color: transparent; }
352
+ .kpi-money .kpi-value, .kpi-money .kpi-label { color: var(--jade-2); }
353
+ .kpi-attention .kpi-value { color: var(--amber); }
354
+ .kpi-quiet .kpi-value { color: var(--ink-3); font-size: 1.3rem; }
355
+
356
+ .block-title {
357
+ font-size: .78rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
358
+ color: var(--ink-3); margin: 30px 0 12px;
359
+ }
360
+
361
+ .approve-all {
362
+ display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
363
+ background: var(--amber-bg); border: 1px solid var(--amber);
364
+ border-radius: var(--radius); padding: 16px 20px; margin-bottom: 20px;
365
+ }
366
+ .approve-all p { flex: 1; min-width: 200px; font-size: .92rem; color: var(--amber); }
367
+ .approve-all b { font-weight: 700; }
368
+
369
+ /* Pulso del periodo */
370
+ .chart {
371
+ background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
372
+ padding: 16px 18px 10px;
373
+ }
374
+ .chart-bars {
375
+ display: flex; align-items: flex-end; gap: 3px; height: 68px;
376
+ }
377
+ .chart-bars .bar {
378
+ flex: 1; background: var(--jade); border-radius: 3px 3px 0 0; min-height: 3px;
379
+ opacity: .85;
380
+ }
381
+ .chart-bars .bar:hover { opacity: 1; }
382
+ .chart-axis {
383
+ display: flex; justify-content: space-between;
384
+ font-size: .72rem; color: var(--ink-3); margin-top: 7px;
385
+ font-variant-numeric: tabular-nums;
386
+ }
387
+
388
+ /* Lista de proyectos */
389
+ .plist { display: flex; flex-direction: column; gap: 8px; }
390
+ .prow {
391
+ background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
392
+ padding: 15px 18px; display: flex; align-items: center; gap: 18px;
393
+ }
394
+ .prow:hover { border-color: var(--line-2); }
395
+ .prow-text { flex: 1; min-width: 0; }
396
+ .prow-name {
397
+ font-size: 1rem; font-weight: 580; letter-spacing: -.01em;
398
+ display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
399
+ }
400
+ .prow-meta {
401
+ font-size: .83rem; color: var(--ink-3); margin-top: 3px;
402
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
403
+ }
404
+ .prow-figs { text-align: right; flex: none; }
405
+ .prow-hours {
406
+ font-size: 1.05rem; font-weight: 580; font-variant-numeric: tabular-nums;
407
+ white-space: nowrap;
408
+ }
409
+ .prow-amount {
410
+ font-size: .85rem; color: var(--jade-2); font-weight: 600; margin-top: 2px;
411
+ font-variant-numeric: tabular-nums; white-space: nowrap;
412
+ }
413
+
414
+ .tag {
415
+ display: inline-block; font-size: .72rem; font-weight: 600;
416
+ padding: 2px 8px; border-radius: 999px;
417
+ background: var(--card-2); color: var(--ink-3);
418
+ }
419
+ .tag-warn { background: var(--amber-bg); color: var(--amber); }
420
+
421
+ /* Actividad reciente */
422
+ .feed { display: flex; flex-direction: column; gap: 1px;
423
+ background: var(--line); border: 1px solid var(--line);
424
+ border-radius: var(--radius); overflow: hidden; }
425
+ .act {
426
+ display: flex; align-items: baseline; gap: 11px;
427
+ padding: 11px 16px; background: var(--card); font-size: .88rem;
428
+ }
429
+ .act code {
430
+ font-family: ui-monospace, Menlo, monospace; font-size: .78rem; flex: none;
431
+ color: var(--jade-2); background: var(--jade-bg); padding: 1px 6px; border-radius: 5px;
432
+ }
433
+ .act-subject { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
434
+ .act-repo { color: var(--ink-3); font-size: .8rem; flex: none; }
435
+ .act-diff {
436
+ color: var(--ink-3); font-size: .78rem; flex: none;
437
+ font-variant-numeric: tabular-nums; font-family: ui-monospace, Menlo, monospace;
438
+ }
439
+ .act-when { color: var(--ink-3); font-size: .78rem; flex: none; min-width: 48px; text-align: right; }
440
+
441
+ /* ── Informes ───────────────────────────────────────────────────────── */
442
+
443
+ .report {
444
+ background: var(--card); border: 1px solid var(--line);
445
+ border-radius: var(--radius); padding: 20px 22px; margin-bottom: 10px;
446
+ display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
447
+ }
448
+ .report-text { flex: 1; min-width: 160px; }
449
+ .report-name { font-size: 1.05rem; font-weight: 600; letter-spacing: -.01em; }
450
+ .report-client { font-size: .87rem; color: var(--ink-3); margin-top: 2px; }
451
+ .report-figs { text-align: right; }
452
+ .report-hours {
453
+ font-size: 1.5rem; font-weight: 640; letter-spacing: -.03em;
454
+ font-variant-numeric: tabular-nums;
455
+ }
456
+ .report-amount { font-size: .85rem; color: var(--jade-2); font-weight: 600; margin-top: 2px; }
457
+ .report-cmd {
458
+ width: 100%; font-family: ui-monospace, Menlo, monospace; font-size: .78rem;
459
+ color: var(--ink-3); background: var(--card-2);
460
+ padding: 9px 12px; border-radius: 8px; overflow-x: auto; white-space: nowrap;
461
+ }
462
+ .note {
463
+ font-size: .87rem; color: var(--ink-3); margin-top: 18px;
464
+ max-width: 58ch; line-height: 1.5;
465
+ }
466
+
467
+ .top-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
468
+
469
+ /* Botón de actualizar. Discreto: es una red de seguridad, no la forma normal
470
+ de usar la aplicación — al volver a la pestaña ya se actualiza sola. */
471
+ .sync {
472
+ display: inline-flex; align-items: center; gap: 7px;
473
+ font: inherit; font-size: .83rem; color: var(--ink-2);
474
+ background: var(--card); border: 1px solid var(--line);
475
+ border-radius: 999px; padding: 6px 13px 6px 11px; cursor: pointer;
476
+ }
477
+ .sync:hover { color: var(--ink); border-color: var(--line-2); }
478
+ .sync-dot {
479
+ width: 7px; height: 7px; border-radius: 50%;
480
+ background: var(--jade); flex: none;
481
+ }
482
+ .sync.is-busy { color: var(--ink-3); cursor: default; }
483
+ .sync.is-busy .sync-dot { animation: sync-pulse 1s ease-in-out infinite; }
484
+
485
+ @keyframes sync-pulse {
486
+ 0%, 100% { opacity: 1; transform: scale(1); }
487
+ 50% { opacity: .35; transform: scale(.7); }
488
+ }
489
+
490
+ /* Un import que falla deja los datos viejos en pantalla sin avisar. Este es
491
+ el aviso: si no se puede actualizar, hay que saberlo antes de fiarse de
492
+ una cifra. */
493
+ .sync-warn {
494
+ font-size: .8rem; color: var(--danger);
495
+ background: var(--card); border: 1px solid var(--danger);
496
+ border-radius: 999px; padding: 4px 11px;
497
+ }
498
+
499
+ @media (prefers-reduced-motion: reduce) {
500
+ .sync.is-busy .sync-dot { animation: none; opacity: .4; }
501
+ }
502
+
503
+ /* ── Proyectos ──────────────────────────────────────────────────────── */
504
+
505
+ .stale {
506
+ background: var(--amber-bg); border: 1px solid var(--amber);
507
+ border-radius: var(--radius); padding: 16px 20px; margin-bottom: 16px;
508
+ color: var(--amber);
509
+ }
510
+ .stale p { font-size: .92rem; line-height: 1.5; }
511
+ .stale ul { margin: 10px 0; padding-left: 20px; font-size: .89rem; }
512
+ .stale li { margin-bottom: 3px; }
513
+ .stale-fix { font-size: .87rem; opacity: .9; }
514
+ .share-btn.is-stale { border-color: var(--amber); color: var(--amber); font-weight: 600; }
515
+ .stale-mark { color: var(--amber); font-weight: 700; }
516
+
517
+ .pcard {
518
+ background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
519
+ padding: 18px 20px; margin-bottom: 10px;
520
+ }
521
+ .pcard-head { display: flex; align-items: flex-start; gap: 16px; }
522
+ .pcard-head > div:first-child { flex: 1; min-width: 0; }
523
+ .pcard-name { font-size: 1.05rem; font-weight: 600; letter-spacing: -.01em; }
524
+ .pcard-meta { font-size: .85rem; color: var(--ink-3); margin-top: 2px; }
525
+ .pcard-rate { text-align: right; flex: none; }
526
+ .pcard-rate-v {
527
+ font-size: 1.1rem; font-weight: 620; color: var(--jade-2);
528
+ font-variant-numeric: tabular-nums; white-space: nowrap;
529
+ }
530
+ .pcard-warn { font-size: .85rem; color: var(--amber); margin-top: 10px; }
531
+ .repos { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
532
+ .repos code {
533
+ font-family: ui-monospace, Menlo, monospace; font-size: .76rem; color: var(--ink-3);
534
+ background: var(--card-2); padding: 3px 8px; border-radius: 6px;
535
+ max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
536
+ }
537
+ .rate-hist {
538
+ display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px;
539
+ font-size: .78rem; color: var(--ink-3);
540
+ }
541
+
542
+ .share-block {
543
+ margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
544
+ display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
545
+ }
546
+ .share-hint { font-size: .82rem; color: var(--ink3, var(--ink-3)); }
547
+ .share-out { width: 100%; margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
548
+ .share-line { font-size: .87rem; color: var(--ink-2); }
549
+ .share-line code, .cmd {
550
+ font-family: ui-monospace, Menlo, monospace; font-size: .78rem;
551
+ background: var(--card-2); padding: 3px 7px; border-radius: 5px; color: var(--ink-2);
552
+ }
553
+ .cmd { display: block; padding: 9px 12px; overflow-x: auto; white-space: nowrap; }
554
+ .share-warn {
555
+ font-size: .82rem; color: var(--amber); background: var(--amber-bg);
556
+ border-radius: 8px; padding: 9px 12px; line-height: 1.5;
557
+ }
558
+ .share-warn code { background: transparent; padding: 0; color: inherit; font-weight: 600; }
559
+
560
+ .rateform {
561
+ display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
562
+ margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
563
+ font-size: .85rem; color: var(--ink-3);
564
+ }
565
+ .rateform input {
566
+ border: 1px solid var(--line-2); border-radius: 7px; padding: 6px 9px;
567
+ background: var(--paper); color: var(--ink); font: inherit; font-size: .88rem;
568
+ }
569
+ .rateform input[type="number"] { width: 80px; }
570
+
571
+ .orphans {
572
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
573
+ gap: 8px; margin-bottom: 4px;
574
+ }
575
+ .orphan {
576
+ border: 1px solid var(--line-2); border-radius: 9px; padding: 10px 12px;
577
+ text-align: left; background: var(--paper);
578
+ }
579
+ .orphan:hover { border-color: var(--jade); background: var(--jade-bg); }
580
+ .orphan.is-on { border-color: var(--jade); background: var(--jade-bg); }
581
+ .orphan-name {
582
+ display: block; font-size: .92rem; font-weight: 580;
583
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
584
+ }
585
+ .orphan-meta { display: block; font-size: .76rem; color: var(--ink-3); margin-top: 2px; }
586
+
587
+ .authorbox {
588
+ margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
589
+ display: flex; flex-wrap: wrap; gap: 7px; align-items: center;
590
+ }
591
+ .authorbox .addform-hint { width: 100%; margin-bottom: 4px; }
592
+ .author-pick { font-family: ui-monospace, Menlo, monospace; font-size: .8rem; }
593
+ .author-n {
594
+ font-size: .72rem; color: var(--ink-3); background: var(--card-2);
595
+ padding: 1px 6px; border-radius: 999px; margin-left: 4px;
596
+ }
597
+
598
+ .newproject {
599
+ background: var(--card); border: 1px solid var(--line-2); border-radius: var(--radius);
600
+ padding: 18px 20px; display: flex; flex-direction: column; gap: 13px;
601
+ }
602
+ .newproject .field { display: flex; flex-direction: column; gap: 5px; }
603
+ .newproject .field > span { font-size: .78rem; color: var(--ink-3); font-weight: 600; }
604
+ .newproject input, .newproject select {
605
+ border: 1px solid var(--line-2); border-radius: 8px; padding: 9px 11px;
606
+ background: var(--paper); color: var(--ink); font: inherit; font-size: .95rem; width: 100%;
607
+ }
608
+ .np-cur { max-width: 110px; }
609
+
610
+ .report-actions {
611
+ display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
612
+ width: 100%; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
613
+ }
614
+ .report-actions .field { display: flex; flex-direction: column; gap: 4px; }
615
+ .report-actions .field > span { font-size: .74rem; color: var(--ink-3); font-weight: 600; }
616
+ .report-actions input[type="date"], .report-actions input[type="text"] {
617
+ border: 1px solid var(--line-2); border-radius: 7px; padding: 7px 9px;
618
+ background: var(--paper); color: var(--ink); font: inherit; font-size: .88rem;
619
+ }
620
+ .checkline {
621
+ display: flex; align-items: center; gap: 7px; font-size: .85rem;
622
+ color: var(--ink-2); padding-bottom: 8px;
623
+ }
624
+ .report-actions .btn-main { margin-left: auto; padding: 9px 18px; font-size: .9rem; }
625
+
626
+ /* ── Aviso flotante ─────────────────────────────────────────────────── */
627
+
628
+ .toast {
629
+ position: fixed; left: 50%; bottom: 26px; z-index: 40;
630
+ transform: translate(-50%, 70px); opacity: 0;
631
+ background: var(--ink); color: var(--paper);
632
+ padding: 11px 20px; border-radius: 9px; font-size: .93rem; font-weight: 550;
633
+ transition: transform .25s cubic-bezier(.2,.8,.3,1), opacity .25s;
634
+ pointer-events: none;
635
+ }
636
+ .toast.is-on { transform: translate(-50%, 0); opacity: 1; }
637
+
638
+ @media (prefers-reduced-motion: reduce) {
639
+ *, *::before, *::after { transition-duration: .01ms !important; }
640
+ }
641
+
642
+ @media (max-width: 560px) {
643
+ main { padding: 28px 16px 80px; }
644
+ .hero { flex-direction: column; }
645
+ .row-head { padding: 14px 16px; gap: 12px; }
646
+ .row-body { padding-left: 16px; }
647
+ .field-pair { flex-direction: column; }
648
+ .act-repo, .act-diff { display: none; }
649
+ .prow { gap: 12px; }
650
+ }
651
+
652
+ /* ── Equipo ─────────────────────────────────────────────────────────── */
653
+
654
+ /* Cuatro columnas fijas: los KPIs solo se comparan bien si están alineados
655
+ en una fila. En móvil pasan a dos, nunca a una lista vertical — apilados
656
+ dejan de compararse y vuelven a ser datos sueltos, que es el problema que
657
+ esta pantalla venía a resolver. */
658
+ .kpis-4 { grid-template-columns: repeat(4, 1fr); }
659
+ @media (max-width: 900px) { .kpis-4 { grid-template-columns: repeat(2, 1fr); } }
660
+
661
+ /* La etiqueta va ARRIBA y el contexto abajo: se lee "horas del periodo →
662
+ 138h → +11h que el mes pasado", que es el orden en que se entiende. */
663
+ .kpi-ctx { display: flex; flex-direction: column; gap: 2px; }
664
+ .kpi-ctx .kpi-label { margin: 0; order: -1; }
665
+ .kpi-ctx-line {
666
+ font-size: .78rem; color: var(--ink-3); margin-top: 6px; line-height: 1.35;
667
+ }
668
+ .kpi-warn .kpi-value { color: var(--amber); }
669
+
670
+ .alert {
671
+ display: flex; flex-direction: column; gap: 2px;
672
+ border: 1px solid var(--line); border-left-width: 3px;
673
+ border-radius: var(--radius); padding: 12px 16px; margin-bottom: 10px;
674
+ background: var(--card);
675
+ }
676
+ .alert-t { font-weight: 600; font-size: .93rem; }
677
+ .alert-d { font-size: .84rem; color: var(--ink-3); line-height: 1.45; }
678
+ .alert-warn { border-left-color: var(--amber); background: var(--amber-bg); }
679
+ .alert-warn .alert-t, .alert-warn .alert-d { color: var(--amber); }
680
+ .alert-danger { border-left-color: var(--danger); }
681
+ .alert-danger .alert-t { color: var(--danger); }
682
+ .alert-info { border-left-color: var(--line-2); }
683
+
684
+ /* Tabla comparable. El scroll horizontal vive aquí dentro: si lo hiciera el
685
+ body, la página entera se desplazaría en móvil. */
686
+ .tbl-wrap { overflow-x: auto; border: 1px solid var(--line);
687
+ border-radius: var(--radius); background: var(--card); }
688
+ .tbl { width: 100%; border-collapse: collapse; font-size: .9rem; }
689
+ .tbl th {
690
+ text-align: left; font-size: .72rem; letter-spacing: .06em;
691
+ text-transform: uppercase; color: var(--ink-3); font-weight: 600;
692
+ padding: 11px 14px; border-bottom: 1px solid var(--line); white-space: nowrap;
693
+ }
694
+ .tbl td { padding: 11px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }
695
+ .tbl tbody tr:last-child td { border-bottom: none; }
696
+ .tbl tbody tr:hover { background: var(--card-2); }
697
+ /* Cifras alineadas a la derecha y en ancho fijo: así se comparan de un
698
+ vistazo, que es la única razón de que esto sea una tabla. */
699
+ .tbl .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
700
+ .td-name { font-weight: 600; }
701
+ .td-sub { font-size: .78rem; color: var(--ink-3); }
702
+ .money-ai { color: var(--amber); }
703
+ .th-comp { width: 26%; min-width: 130px; }
704
+
705
+ .comp { display: flex; height: 7px; border-radius: 4px; overflow: hidden;
706
+ background: var(--card-2); }
707
+ .seg { display: block; height: 100%; }
708
+ .sw-agent { background: var(--jade); }
709
+ .sw-commit { background: var(--amber); }
710
+ .sw-manual { background: var(--line-2); }
711
+
712
+ .legend { display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
713
+ font-size: .78rem; color: var(--ink-3); margin: 8px 0 0; }
714
+ .legend .sw { width: 9px; height: 9px; border-radius: 2px; display: inline-block;
715
+ margin-left: 10px; }
716
+ .legend .sw:first-child { margin-left: 0; }
717
+
718
+ .block-note { font-weight: 400; font-size: .78rem; color: var(--ink-3);
719
+ text-transform: none; letter-spacing: 0; margin-left: 8px; }
720
+
721
+ /* Medido y estimado no valen lo mismo, y la pantalla no debe dejar que se
722
+ confundan: unas horas estimadas presentadas como medidas es exactamente
723
+ lo que convertiría esto en una herramienta para señalar a alguien. */
724
+ .prec { font-size: .76rem; color: var(--amber); background: var(--amber-bg);
725
+ padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
726
+ .prec-ok { color: var(--jade-2); background: var(--jade-bg); }
727
+
728
+ .br { font-family: ui-monospace, Menlo, monospace; font-size: .74rem;
729
+ background: var(--card-2); padding: 2px 6px; border-radius: 5px;
730
+ color: var(--ink-2); }
731
+ .tag-ok { background: var(--jade-bg); color: var(--jade-2); }
732
+
733
+ .filter {
734
+ font: inherit; font-size: .82rem; color: var(--ink-2);
735
+ background: var(--card); border: 1px solid var(--line);
736
+ border-radius: 8px; padding: 6px 10px; margin-right: 8px; max-width: 190px;
737
+ }
738
+
739
+ .more {
740
+ font: inherit; font-size: .84rem; color: var(--ink-2); cursor: pointer;
741
+ background: var(--card); border: 1px solid var(--line);
742
+ border-radius: 8px; padding: 7px 14px; margin-top: 10px;
743
+ }
744
+ .more:hover { border-color: var(--line-2); color: var(--ink); }
745
+
746
+ .note-inline {
747
+ font-size: .82rem; color: var(--ink-3); line-height: 1.5;
748
+ margin: 0 0 10px; max-width: 78ch;
749
+ }