repos
/ finance-rust master

finance-rust

mirror archived upstream

Single-binary self-hosted market watcher for stocks, ETFs, indexes, and futures: live charts, key stats, fundamentals, SEC filings, and SSE streaming.

axumdockerfinancerustself-hostedsqlitestocksvite

6.3 KB · 358 lines · SCSS Raw History
  1@use "../../base/styles/variables" as *;
  2@use "../../base/styles/mixins" as *;
  3
  4/* ---------- page intro ---------- */
  5.health-lede {
  6  max-width: 64ch;
  7  margin: 10px 0 2px;
  8  color: var(--ink-dim);
  9  font-size: 0.9rem;
 10}
 11
 12.health-asof {
 13  @include eyebrow;
 14  font-size: 0.6rem;
 15}
 16
 17/* ---------- systems verdict (Phase 7) ----------
 18   The distilled top read: a coloured dot + headline + one-line clause. Tones
 19   reuse the semantic good/ok/bad tokens; filled live by the page script. */
 20.health-verdict {
 21  display: flex;
 22  align-items: center;
 23  gap: 14px;
 24  margin: 18px 0 6px;
 25  padding: 14px 16px;
 26  border: 1px solid var(--rule);
 27  border-radius: var(--radius);
 28  background: var(--surface);
 29}
 30
 31.health-verdict[hidden] {
 32  display: none;
 33}
 34
 35.health-verdict__dot {
 36  flex: none;
 37  width: 11px;
 38  height: 11px;
 39  border-radius: 50%;
 40  background: var(--ink-faint);
 41}
 42
 43.health-verdict__head {
 44  margin: 0;
 45  font-size: 1.05rem;
 46  font-weight: 600;
 47  letter-spacing: -0.01em;
 48}
 49
 50.health-verdict__detail {
 51  margin: 2px 0 0;
 52  color: var(--ink-dim);
 53  font-size: 0.85rem;
 54}
 55
 56.health-verdict[data-tone="ok"] {
 57  border-color: var(--up-soft);
 58
 59  .health-verdict__dot { background: var(--up); }
 60}
 61
 62.health-verdict[data-tone="warn"] {
 63  border-color: var(--warn);
 64  background: var(--warn-soft);
 65
 66  .health-verdict__dot { background: var(--warn); animation: pulse 1.2s ease-in-out infinite; }
 67}
 68
 69.health-verdict[data-tone="bad"] {
 70  border-color: var(--down);
 71  background: var(--down-soft);
 72
 73  .health-verdict__dot { background: var(--down); }
 74}
 75
 76/* ---------- "fetching now" banner ---------- */
 77.health-banner {
 78  display: flex;
 79  align-items: center;
 80  gap: 10px;
 81  margin: 16px 0 2px;
 82  padding: 11px 14px;
 83  border: 1px solid var(--warn);
 84  border-radius: var(--radius);
 85  background: var(--warn-soft);
 86  font-weight: 500;
 87  font-size: 0.9rem;
 88}
 89
 90/* `.health-banner` sets display:flex, which would override the [hidden]
 91   attribute's display:none — so re-assert it explicitly. */
 92.health-banner[hidden] {
 93  display: none;
 94}
 95
 96.health-banner__dot {
 97  flex: none;
 98  width: 9px;
 99  height: 9px;
100  border-radius: 50%;
101  background: var(--warn);
102  animation: pulse 1.2s ease-in-out infinite;
103}
104
105/* ---------- status badge ---------- */
106.badge {
107  @include eyebrow;
108  flex: none;
109  padding: 3px 8px;
110  border-radius: 999px;
111  font-size: 0.56rem;
112}
113
114.badge--ok {
115  color: var(--up);
116  background: var(--up-soft);
117}
118
119.badge--bad {
120  color: var(--down);
121  background: var(--down-soft);
122}
123
124.badge--warn {
125  color: var(--warn);
126  background: var(--warn-soft);
127}
128
129.badge--idle {
130  color: var(--ink-faint);
131  background: var(--well);
132}
133
134/* ---------- endpoints ----------
135   Phase 31: an explicit 3-up at desktop, 2-up at tablet, 1-up at phone,
136   so the SEC / Stooq / Yahoo cards always read in a tidy grid rather
137   than the previous auto-fit which dropped to 1-up at narrow desktops. */
138.endpoint-grid {
139  display: grid;
140  grid-template-columns: 1fr;
141  gap: var(--sp-3);
142}
143
144@media (min-width: $bp-sm) {
145  .endpoint-grid {
146    grid-template-columns: repeat(2, minmax(0, 1fr));
147  }
148}
149
150@media (min-width: $bp-md) {
151  .endpoint-grid {
152    grid-template-columns: repeat(3, minmax(0, 1fr));
153  }
154}
155
156.endpoint {
157  @include card;
158  padding: var(--sp-4);
159}
160
161.endpoint__head,
162.job__head {
163  display: flex;
164  align-items: baseline;
165  justify-content: space-between;
166  gap: 12px;
167}
168
169.endpoint__head h3,
170.job__id h3 {
171  font-size: 1rem;
172}
173
174/* request-budget meter */
175.meter {
176  margin: 16px 0 2px;
177}
178
179.meter__row {
180  display: flex;
181  align-items: baseline;
182  justify-content: space-between;
183  gap: 10px;
184  margin-bottom: 7px;
185}
186
187.meter__count {
188  font-size: 0.82rem;
189  font-weight: 600;
190}
191
192.meter__track {
193  height: 8px;
194}
195
196/* budget fill warms then reddens as the hourly ceiling nears */
197.track__fill--warn {
198  background: var(--warn);
199}
200
201.track__fill--bad {
202  background: var(--down);
203}
204
205.meter__note {
206  margin-top: 7px;
207  color: var(--ink-faint);
208  font-size: 0.74rem;
209}
210
211/* ---------- key-value rows (shared by endpoints and jobs) ---------- */
212.kvs {
213  margin-top: 12px;
214}
215
216.kv {
217  display: flex;
218  align-items: baseline;
219  justify-content: space-between;
220  gap: 12px;
221  padding: 7px 0;
222  border-top: 1px solid var(--rule);
223  font-size: 0.85rem;
224}
225
226.kv dt {
227  color: var(--ink-dim);
228}
229
230.kv dd {
231  font-weight: 600;
232  text-align: right;
233}
234
235.kv--err {
236  flex-direction: column;
237  align-items: stretch;
238}
239
240.kv--err dd {
241  font-weight: 400;
242  text-align: left;
243  color: var(--down);
244  word-break: break-word;
245}
246
247.kv--err .muted {
248  color: var(--ink-faint);
249  white-space: nowrap;
250}
251
252/* ---------- background jobs ---------- */
253.job-list {
254  display: flex;
255  flex-direction: column;
256  gap: 10px;
257}
258
259.job {
260  @include card;
261  padding: 14px 16px;
262}
263
264/* a job mid-fetch is rimmed in the working amber, echoing the banner */
265.job--active {
266  border-color: var(--warn);
267}
268
269.job__id p {
270  margin-top: 3px;
271  color: var(--ink-dim);
272  font-size: 0.8rem;
273}
274
275/* ---------- activity log ---------- */
276.log {
277  @include card;
278  padding: 2px 14px;
279}
280
281.logrows {
282  margin: 0;
283  padding: 0;
284  list-style: none;
285}
286
287.logrow {
288  display: flex;
289  align-items: baseline;
290  flex-wrap: wrap;
291  gap: var(--sp-1) var(--sp-3);
292  padding: 8px 0;
293  border-top: 1px solid var(--rule);
294  font-size: var(--fs-sm);
295  /* routine `ok` rows mute their entire body; the time, job, detail and
296     meta all drop a tier so the eye glides past them and lands on
297     anything coloured. */
298  color: var(--ink-faint);
299}
300
301.logrow:first-child {
302  border-top: none;
303}
304
305.logrow__time {
306  @include mono;
307  color: var(--ink-faint);
308  font-size: var(--fs-xs);
309}
310
311.logrow__job {
312  @include mono;
313  min-width: 6ch;
314  font-weight: 600;
315  color: var(--ink-dim);
316  font-size: var(--fs-xs);
317  text-transform: uppercase;
318  letter-spacing: 0.05em;
319}
320
321.logrow__detail {
322  flex: 1 1 14ch;
323  min-width: 0;
324  color: var(--ink-dim);
325}
326
327/* a failed fetch should catch the eye down the tail; the row's job pill
328   and detail both pop, the time/meta stay quiet. */
329.logrow--bad .logrow__job {
330  color: var(--down);
331}
332
333.logrow--bad .logrow__detail {
334  color: var(--down);
335  font-weight: 500;
336}
337
338.logrow__meta {
339  color: var(--ink-faint);
340  font-size: var(--fs-2xs);
341}
342
343/* ---------- empty states ---------- */
344.health-empty {
345  @include card;
346  padding: 22px;
347  color: var(--ink-dim);
348  font-size: 0.9rem;
349  text-align: center;
350}
351
352/* ---------- desktop ---------- */
353@media (min-width: $bp-md) {
354  .logrow__job {
355    min-width: 9ch;
356  }
357}