relic-mcp 0.11.0 → 0.12.1

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.
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "relic",
12
12
  "description": "Publish a file from your machine as an encrypted, shareable link. The agent encrypts locally, uploads only ciphertext, and hands back a URL whose fragment holds the key, so the service stores something it cannot read.",
13
- "version": "0.11.0",
13
+ "version": "0.12.1",
14
14
  "source": "./",
15
15
  "author": {
16
16
  "name": "The Bushido Collective",
@@ -21,6 +21,6 @@
21
21
  }
22
22
  ],
23
23
  "metadata": {
24
- "version": "0.11.0"
24
+ "version": "0.12.1"
25
25
  }
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relic",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "Publish a file from your machine as an encrypted, shareable link. The agent encrypts locally, uploads only ciphertext, and hands back a URL whose fragment holds the key, so the service stores something it cannot read.",
5
5
  "mcpServers": "./mcp-servers.json",
6
6
  "author": {
package/README.md CHANGED
@@ -42,7 +42,8 @@ For any client that takes a JSON config:
42
42
  this machine later. See [Republishing](#republishing). The service never
43
43
  receives the key or the token plaintext; it keeps only a SHA-256 of the
44
44
  token.
45
-
45
+ 7. Returns a shareable URL whose fragment holds the decryption key. Fragments
46
+ are never sent to a server by a browser.
46
47
  Call the `relic_describe_client` tool and it will tell you all of this itself,
47
48
  without reading a file or making a request.
48
49
 
@@ -179,9 +180,10 @@ relic plaintext leaves the machine during rendering.
179
180
  | `relic_lookup_source` | `path` | Reads local state to find whether this machine already published that file, and returns the exact `relic_republish` call. Calls no server. |
180
181
  | `relic_list` | optional `limit`, `include_expired`, `verify`, `refresh` | Every relic this machine published, newest first. The only tool that enumerates: lookup answers only from the file a relic came from. A name this machine never recorded is recovered by decrypting the relic's own envelope in one 64 KB range request, or comes back `null` with the reason. A relic the service will not serve is listed with which of removed, expired, exhausted, or unreachable it is. Each row carries the share URL, fragment included, so each row is a credential. Reaching the service spends one of a relic's finite opens; recovered names are cached, so a repeat listing spends none. |
181
182
  | `relic_show` | `relic_id`, optional `include_content` | One relic in detail, including how many versions the service holds against how many this machine recorded, and with `include_content` the current decrypted content. Read it before republishing anything you did not just write: republish replaces what the link serves, so without the read-back the edit is blind. Content that is not valid UTF-8 is reported as size and type rather than mangled text. |
182
- | `relic_republish` | `relic_id`, `path`, optional `filename`, `title`, `cover`, `ttl_days` | Publishes a new version under the same key, so the share URL is unchanged. Replaces the plaintext title (defaults to the new filename; pass `""` to remove it). Replaces the cover image with a newly rendered cover, or clears it if `cover: false` is passed. Works only on the machine holding that relic's key and publish token; a taken-down relic can never be revived. |
183
+ | `relic_republish` | `relic_id`, `path`, optional `filename`, `title`, `cover`, `ttl_days`, `addresses`, `notify` | Publishes a new version under the same key, so the share URL is unchanged. Replaces the plaintext title (defaults to the new filename; pass `""` to remove it). Replaces the cover image with a newly rendered cover, or clears it if `cover: false` is passed. Sends a change notice email to everyone following the relic unless `notify: false` is passed. At most one email per person per relic per 10 minutes is sent, and one stop link stops every email about that relic. Works only on the machine holding that relic's key and publish token; a taken-down relic can never be revived. |
184
+ | `relic_share` | `relic_id`, `emails` | Send a relic this machine published to named people. Registers up to 20 email addresses with the service for change and comment notices, and returns a composed share email and mailto link to draft in the sharer's own mailbox. Addresses are stored in the clear by the service, linked to the relic id. A new comment emails everyone on the list except the author, naming the commenter's address (or 'The publisher'). At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Relic never sends the share email. Readers holding the link can also share from the viewer once this client version has published or republished the relic. |
183
185
  | `relic_read_comments` | `relic_id` | Returns the relic's comments oldest first, decrypted locally, with the author and a count of any that would not decrypt. Works only on the machine that published. |
184
- | `relic_comment` | `relic_id`, `body`, optional `display_name` | Leaves a comment, encrypted on this machine, authorized by the publish token and attributed as `publisher`. Body caps at 4096 bytes of UTF-8. |
186
+ | `relic_comment` | `relic_id`, `body`, optional `display_name` | Leaves a comment, encrypted on this machine, authorized by the publish token and attributed as `publisher`. Warning: posting emails everyone following the relic, naming 'The publisher'. At most one email per person per relic per 10 minutes, and one stop link stops every email about that relic. Body caps at 4096 bytes of UTF-8. |
185
187
  | `relic_describe_client` | none | Explains the encryption path. Reads nothing, sends nothing. |
186
188
 
187
189
  ## Environment
@@ -10996,6 +10996,8 @@ function foldAliases(lowered) {
10996
10996
  }
10997
10997
  return out;
10998
10998
  }
10999
+ // ../relic-format/src/share.ts
11000
+ var SHARE_PROOF_INFO = new TextEncoder().encode("relic/share-proof/v1");
10999
11001
  // ../relic-viewer/src/sandbox.ts
11000
11002
  var React3 = __toESM(require_react(), 1);
11001
11003
  var import_client = __toESM(require_client(), 1);
@@ -254,6 +254,10 @@ body {
254
254
  position: absolute;
255
255
  z-index: 8;
256
256
  background: var(--surface);
257
+ /* Its own ink rather than whatever it inherits. Inside a fullscreen stage
258
+ the surface is dark and the page around it is not, and an inherited ink
259
+ put the comment's own words dark on dark. */
260
+ color: var(--ink);
257
261
  border: 1px solid var(--rule-strong);
258
262
  box-shadow: 0 6px 18px rgb(0 0 0 / 14%);
259
263
  font-family: var(--sans);
@@ -332,6 +336,14 @@ body {
332
336
  list-style: none;
333
337
  }
334
338
 
339
+ /* The card lights the row it opened for, and the light runs edge to edge of
340
+ the row. The sidebar has margins around its rows; a card has none, so the
341
+ row brings its own and the author and the date stop touching the light. */
342
+ .popover-thread .comment {
343
+ padding-right: 0.6rem;
344
+ padding-left: 0.6rem;
345
+ }
346
+
335
347
  .popover-target {
336
348
  margin: 0 0 0.4rem;
337
349
  color: var(--ink-soft);
@@ -367,6 +379,68 @@ body {
367
379
  font-size: 0.72rem;
368
380
  }
369
381
 
382
+ /* The comments that share one cluster on the timeline. Each row opens that
383
+ comment's own card, so a row is a button that reads as the sidebar's
384
+ comment head shrunk to one line plus the start of what was said. */
385
+ .popover-members {
386
+ margin: 0;
387
+ padding: 0;
388
+ list-style: none;
389
+ }
390
+
391
+ .popover-members li + li {
392
+ border-top: 1px solid var(--rule);
393
+ }
394
+
395
+ .popover-member {
396
+ display: grid;
397
+ grid-template-columns: auto minmax(0, 1fr);
398
+ column-gap: 0.6rem;
399
+ row-gap: 0.15rem;
400
+ width: 100%;
401
+ padding: 0.45rem 0.3rem;
402
+ background: none;
403
+ border: 0;
404
+ color: var(--ink);
405
+ font: inherit;
406
+ text-align: left;
407
+ cursor: pointer;
408
+ }
409
+
410
+ .popover-member:hover {
411
+ background: color-mix(in srgb, var(--patina) 12%, transparent);
412
+ }
413
+
414
+ .popover-member:focus-visible {
415
+ outline: 2px solid var(--patina);
416
+ outline-offset: -2px;
417
+ }
418
+
419
+ .popover-member-time {
420
+ font-family: var(--mono);
421
+ font-size: 0.72rem;
422
+ color: var(--patina);
423
+ }
424
+
425
+ .popover-member-author {
426
+ overflow: hidden;
427
+ font-family: var(--mono);
428
+ font-size: 0.72rem;
429
+ color: var(--ink-soft);
430
+ white-space: nowrap;
431
+ text-overflow: ellipsis;
432
+ }
433
+
434
+ .popover-member-body {
435
+ grid-column: 1 / -1;
436
+ display: -webkit-box;
437
+ overflow: hidden;
438
+ font-family: var(--serif);
439
+ font-size: 0.86rem;
440
+ -webkit-box-orient: vertical;
441
+ -webkit-line-clamp: 2;
442
+ }
443
+
370
444
  /* ---------- the accession band ---------- */
371
445
 
372
446
  .bar {
@@ -702,6 +776,16 @@ body {
702
776
  margin: 0 auto;
703
777
  }
704
778
 
779
+ /* A markdown relic is a document, so it gets the width of a document: a
780
+ letter page, the 8.5in sheet Google Docs lays out and a printer feeds. The
781
+ 46rem column above is narrower than that page, and it read as a strip down
782
+ the middle of the window. The notice is widened with it so the explanation
783
+ above the document lines up with the document it explains. */
784
+ .stage-markdown .doc,
785
+ .stage-markdown .notice {
786
+ max-width: 8.5in;
787
+ }
788
+
705
789
  .toggle-row {
706
790
  display: flex;
707
791
  justify-content: flex-end;
@@ -1148,6 +1232,14 @@ body {
1148
1232
  white-space: nowrap;
1149
1233
  }
1150
1234
 
1235
+ /* A panel open over the scrubber already names the time it is about, and it
1236
+ sits exactly where this readout does: the readout's lower edge would show
1237
+ under the panel as a stray notch. The rule and the comment button stay, so
1238
+ a reader can still aim somewhere else. */
1239
+ .stage-wrap:has(.popover) .hover-timecode {
1240
+ visibility: hidden;
1241
+ }
1242
+
1151
1243
  .timeline-hover-comment-btn {
1152
1244
  position: absolute;
1153
1245
  top: calc(100% + 4px);
@@ -1285,6 +1377,10 @@ body {
1285
1377
  .media-stage:fullscreen {
1286
1378
  color-scheme: dark;
1287
1379
  --surface: #171b1c;
1380
+ /* Below the band rather than above it: a comment field in a panel on the
1381
+ stage sits on the ground, and the page's light ground under the stage's
1382
+ light ink made what was typed there unreadable. */
1383
+ --ground: #0e1112;
1288
1384
  --ink: #e6e9e7;
1289
1385
  --ink-soft: #969e9d;
1290
1386
  --rule: #3b4345;
@@ -3068,6 +3164,266 @@ canvas.relic-page {
3068
3164
  }
3069
3165
  }
3070
3166
 
3167
+ /* ---------- the share panel ---------- */
3168
+
3169
+ /* A sheet that drops from the band, under the action that opened it. It is a
3170
+ modal dialog rather than a third sidebar: sharing is a short errand with an
3171
+ end, the reading row already has a conversation beside it, and a dialog
3172
+ gives the keyboard its trap and Escape for nothing. Square, hairline, the
3173
+ patina rule on top like the composer, and the version list's shadow, so it
3174
+ reads as the same family of chrome as everything else that drops from the
3175
+ band. */
3176
+ .share-panel {
3177
+ position: fixed;
3178
+ inset: var(--share-top, var(--bar-height)) 0 auto auto;
3179
+ width: min(28rem, 100vw);
3180
+ max-width: 100vw;
3181
+ max-height: calc(100dvh - var(--share-top, var(--bar-height)));
3182
+ margin: 0;
3183
+ padding: 0;
3184
+ overflow-y: auto;
3185
+ overscroll-behavior: contain;
3186
+ color: var(--ink);
3187
+ font-family: var(--sans);
3188
+ background: var(--surface);
3189
+ border: 1px solid var(--rule-strong);
3190
+ border-top: 2px solid var(--patina);
3191
+ border-right: 0;
3192
+ box-shadow: 0 6px 18px rgb(0 0 0 / 18%);
3193
+ }
3194
+
3195
+ .share-panel::backdrop {
3196
+ background: rgb(16 19 20 / 28%);
3197
+ }
3198
+
3199
+ .share-head {
3200
+ position: sticky;
3201
+ top: 0;
3202
+ z-index: 1;
3203
+ display: flex;
3204
+ align-items: center;
3205
+ justify-content: space-between;
3206
+ gap: 0.75rem;
3207
+ min-height: 2.75rem;
3208
+ padding: 0 0.4rem 0 1.25rem;
3209
+ background: var(--surface);
3210
+ border-bottom: 1px solid var(--rule);
3211
+ }
3212
+
3213
+ .share-title {
3214
+ margin: 0;
3215
+ font-size: 1rem;
3216
+ font-weight: 600;
3217
+ }
3218
+
3219
+ .share-title:focus {
3220
+ outline: none;
3221
+ }
3222
+
3223
+ .share-close {
3224
+ display: inline-flex;
3225
+ align-items: center;
3226
+ justify-content: center;
3227
+ width: 2.25rem;
3228
+ height: 2.25rem;
3229
+ padding: 0;
3230
+ color: var(--ink-soft);
3231
+ background: transparent;
3232
+ border: 0;
3233
+ cursor: pointer;
3234
+ }
3235
+
3236
+ .share-close:hover {
3237
+ color: var(--patina-ink);
3238
+ background: var(--ground);
3239
+ }
3240
+
3241
+ .share-close:focus-visible {
3242
+ outline: 2px solid var(--patina);
3243
+ outline-offset: -2px;
3244
+ }
3245
+
3246
+ .share-body {
3247
+ display: grid;
3248
+ gap: 0.75rem;
3249
+ padding: 1.1rem 1.25rem 1.4rem;
3250
+ }
3251
+
3252
+ .share-body > * {
3253
+ min-width: 0;
3254
+ }
3255
+
3256
+ .share-form {
3257
+ display: grid;
3258
+ gap: 0.75rem;
3259
+ margin: 0;
3260
+ }
3261
+
3262
+ .share-form > .action.primary,
3263
+ .share-body > .action {
3264
+ justify-self: start;
3265
+ }
3266
+
3267
+ .share-body .thread-note,
3268
+ .share-body .thread-policy {
3269
+ margin: 0;
3270
+ }
3271
+
3272
+ .share-body .compose-warning {
3273
+ margin: 0;
3274
+ }
3275
+
3276
+ /* The two facts a sharer is owed before typing anybody's address, set as the
3277
+ composer sets its disclosure: at reading size, on the oxide rule. */
3278
+ .share-facts {
3279
+ display: grid;
3280
+ gap: 0.4rem;
3281
+ }
3282
+
3283
+ .share-facts p {
3284
+ margin: 0;
3285
+ }
3286
+
3287
+ .share-addresses {
3288
+ min-height: 4.6rem;
3289
+ font-family: var(--mono);
3290
+ font-size: 0.8rem;
3291
+ line-height: 1.6;
3292
+ resize: vertical;
3293
+ }
3294
+
3295
+ .share-addresses[aria-invalid="true"] {
3296
+ border-color: var(--oxide);
3297
+ }
3298
+
3299
+ /* Inside the sheet every action is a bordered button: the band's divider
3300
+ rules mean nothing away from the band. */
3301
+ .share-panel .action {
3302
+ justify-content: center;
3303
+ padding: 0.5rem 0.85rem;
3304
+ border: 1px solid var(--rule-strong);
3305
+ }
3306
+
3307
+ .share-panel .action.primary {
3308
+ border: 1px solid var(--patina);
3309
+ }
3310
+
3311
+ .share-panel .action:disabled {
3312
+ color: var(--ink-soft);
3313
+ background: var(--ground);
3314
+ border-color: var(--rule);
3315
+ cursor: default;
3316
+ }
3317
+
3318
+ .share-panel .action span {
3319
+ display: inline;
3320
+ }
3321
+
3322
+ .share-panel .compose-foot .action.primary {
3323
+ margin-left: auto;
3324
+ }
3325
+
3326
+ .share-done {
3327
+ margin: 0;
3328
+ padding: 0.6rem 0.75rem;
3329
+ font-size: 0.84rem;
3330
+ line-height: 1.5;
3331
+ background: var(--diff-added);
3332
+ border-left: 2px solid var(--patina);
3333
+ }
3334
+
3335
+ /* The email as the recipient will get it, so what is about to leave the
3336
+ sharer's own mailbox is read before it leaves. The body is set in the
3337
+ reading face because it is a letter, not chrome. */
3338
+ .share-email {
3339
+ margin: 0;
3340
+ background: var(--ground);
3341
+ border: 1px solid var(--rule);
3342
+ }
3343
+
3344
+ .share-email-head {
3345
+ display: grid;
3346
+ grid-template-columns: auto minmax(0, 1fr);
3347
+ gap: 0.3rem 0.75rem;
3348
+ margin: 0;
3349
+ padding: 0.65rem 0.8rem;
3350
+ font-size: 0.82rem;
3351
+ border-bottom: 1px solid var(--rule);
3352
+ }
3353
+
3354
+ .share-email-head dt {
3355
+ padding-top: 0.15rem;
3356
+ color: var(--ink-soft);
3357
+ font-family: var(--mono);
3358
+ font-size: 0.66rem;
3359
+ letter-spacing: 0.14em;
3360
+ text-transform: uppercase;
3361
+ }
3362
+
3363
+ .share-email-head dd {
3364
+ margin: 0;
3365
+ overflow-wrap: anywhere;
3366
+ }
3367
+
3368
+ .share-email-body {
3369
+ margin: 0;
3370
+ padding: 0.75rem 0.8rem 0.85rem;
3371
+ font-family: var(--serif);
3372
+ font-size: 0.9rem;
3373
+ line-height: 1.55;
3374
+ white-space: pre-wrap;
3375
+ overflow-wrap: anywhere;
3376
+ }
3377
+
3378
+ .share-send {
3379
+ display: flex;
3380
+ flex-wrap: wrap;
3381
+ gap: 0.5rem;
3382
+ }
3383
+
3384
+ .share-again {
3385
+ justify-self: start;
3386
+ padding: 0;
3387
+ color: var(--patina-ink);
3388
+ font: inherit;
3389
+ font-size: 0.8rem;
3390
+ text-decoration: underline;
3391
+ text-underline-offset: 2px;
3392
+ background: none;
3393
+ border: 0;
3394
+ cursor: pointer;
3395
+ }
3396
+
3397
+ .share-again:focus-visible {
3398
+ outline: 2px solid var(--patina);
3399
+ outline-offset: 2px;
3400
+ }
3401
+
3402
+ .share-body .thread-refusal {
3403
+ margin: 0;
3404
+ }
3405
+
3406
+ /* A phone gets the whole width under the band, and the buttons stack so the
3407
+ one that opens the mail app is never a sliver. */
3408
+ @media (max-width: 34rem) {
3409
+ .share-panel {
3410
+ width: 100vw;
3411
+ border-left: 0;
3412
+ }
3413
+
3414
+ .share-head {
3415
+ padding-left: 1rem;
3416
+ }
3417
+
3418
+ .share-body {
3419
+ padding: 1rem 1rem 1.25rem;
3420
+ }
3421
+
3422
+ .share-send .action {
3423
+ flex: 1 1 100%;
3424
+ }
3425
+ }
3426
+
3071
3427
  /* ---------- toast ---------- */
3072
3428
 
3073
3429
  .toast {
@@ -3165,6 +3521,11 @@ canvas.relic-page {
3165
3521
  pointer-events: none;
3166
3522
  }
3167
3523
 
3524
+ /* Markers are drawn in ink inside a ring of the surface. The played bar is
3525
+ patina and the unplayed rail a light tint of the ink, so a patina marker
3526
+ vanished over everything already played. Ink stands off the tinted rail,
3527
+ the surface ring stands off the patina, and the pair holds in the dark
3528
+ fullscreen stage, where both tokens are redefined. */
3168
3529
  .time-marker {
3169
3530
  position: absolute;
3170
3531
  top: 50%;
@@ -3173,20 +3534,21 @@ canvas.relic-page {
3173
3534
  padding: 0;
3174
3535
  border: none;
3175
3536
  border-radius: 0;
3176
- background: var(--patina);
3537
+ background: var(--ink);
3177
3538
  transform: translate(-50%, -50%);
3178
3539
  pointer-events: auto;
3179
3540
  cursor: pointer;
3180
3541
  z-index: 2;
3181
- box-shadow: none;
3542
+ box-shadow: 0 0 0 1px var(--surface);
3182
3543
  }
3183
3544
 
3184
3545
  .time-marker:hover,
3185
3546
  .time-marker.is-active,
3186
3547
  .time-marker:focus-visible {
3187
3548
  width: 5px;
3188
- background: var(--patina-ink);
3549
+ background: var(--ink);
3189
3550
  outline: 1px solid var(--patina);
3551
+ outline-offset: 1px;
3190
3552
  z-index: 4;
3191
3553
  }
3192
3554
 
@@ -3195,16 +3557,18 @@ canvas.relic-page {
3195
3557
  border-style: dashed;
3196
3558
  }
3197
3559
 
3560
+ /* A span stands above and below the 4px rail, so its ring shows against the
3561
+ controls band as well as against the rail, played or not. */
3198
3562
  .time-marker-span {
3199
- height: 100%;
3200
- top: 0;
3563
+ height: 8px;
3564
+ top: 50%;
3201
3565
  border-radius: 0;
3202
- border-left: 2px solid var(--patina);
3203
- border-right: 2px solid var(--patina);
3566
+ border-left: 2px solid var(--ink);
3567
+ border-right: 2px solid var(--ink);
3204
3568
  border-top: none;
3205
3569
  border-bottom: none;
3206
- background: color-mix(in srgb, var(--patina) 40%, transparent);
3207
- transform: none;
3570
+ background: var(--ink);
3571
+ transform: translateY(-50%);
3208
3572
  min-width: 4px;
3209
3573
  z-index: 2;
3210
3574
  }
@@ -3212,9 +3576,10 @@ canvas.relic-page {
3212
3576
  .time-marker-span:hover,
3213
3577
  .time-marker-span.is-active,
3214
3578
  .time-marker-span:focus-visible {
3215
- transform: none;
3216
- background: color-mix(in srgb, var(--patina) 75%, transparent);
3579
+ transform: translateY(-50%);
3580
+ background: var(--ink);
3217
3581
  outline: 1px solid var(--patina);
3582
+ outline-offset: 1px;
3218
3583
  z-index: 4;
3219
3584
  }
3220
3585
 
@@ -3230,8 +3595,8 @@ canvas.relic-page {
3230
3595
  padding: 0 3px;
3231
3596
  border: 1px solid var(--surface);
3232
3597
  border-radius: 0;
3233
- background: var(--patina);
3234
- color: #fff;
3598
+ background: var(--ink);
3599
+ color: var(--surface);
3235
3600
  font-family: var(--mono);
3236
3601
  transform: translateY(-50%);
3237
3602
  pointer-events: auto;
@@ -3250,63 +3615,12 @@ canvas.relic-page {
3250
3615
  .time-marker-cluster.is-active,
3251
3616
  .time-marker-cluster:has(.is-active),
3252
3617
  .time-marker-cluster:focus-visible {
3253
- background: var(--patina-ink);
3618
+ background: var(--ink);
3254
3619
  outline: 1px solid var(--patina);
3620
+ outline-offset: 1px;
3255
3621
  z-index: 5;
3256
3622
  }
3257
3623
 
3258
- .timeline-marker-tooltip {
3259
- position: absolute;
3260
- bottom: 100%;
3261
- margin-bottom: 8px;
3262
- transform: translateX(-50%);
3263
- background: var(--surface);
3264
- border: 1px solid var(--rule);
3265
- padding: 0.35rem 0.5rem;
3266
- font-family: var(--sans);
3267
- font-size: 0.74rem;
3268
- color: var(--ink);
3269
- white-space: nowrap;
3270
- pointer-events: none;
3271
- z-index: 20;
3272
- display: flex;
3273
- flex-direction: column;
3274
- gap: 0.2rem;
3275
- }
3276
-
3277
- .marker-tooltip-header {
3278
- display: flex;
3279
- align-items: center;
3280
- gap: 0.5rem;
3281
- }
3282
-
3283
- .marker-tooltip-author {
3284
- font-family: var(--mono);
3285
- font-size: 0.72rem;
3286
- font-weight: 600;
3287
- color: var(--patina);
3288
- }
3289
-
3290
- .marker-tooltip-time {
3291
- font-family: var(--mono);
3292
- font-size: 0.7rem;
3293
- color: var(--ink-soft);
3294
- }
3295
-
3296
- .marker-tooltip-snippet {
3297
- font-family: var(--sans);
3298
- font-size: 0.72rem;
3299
- color: var(--ink);
3300
- max-width: 18rem;
3301
- overflow: hidden;
3302
- text-overflow: ellipsis;
3303
- }
3304
-
3305
- .marker-tooltip-item {
3306
- font-family: var(--sans);
3307
- font-size: 0.7rem;
3308
- color: var(--ink);
3309
- }
3310
3624
  .time-frame-box {
3311
3625
  position: absolute;
3312
3626
  border: 2px solid var(--patina);