@inkbar/theme 0.3.0 → 0.5.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 (3) hide show
  1. package/README.md +7 -8
  2. package/package.json +1 -1
  3. package/theme.css +739 -70
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  ---
22
22
 
23
- `@inkbar/theme` styles the viewer, toolbar controls, note threads and suggestion cards from `@inkbar/vue`, `@inkbar/react`, `@inkbar/svelte` and `createViewer` in `@inkbar/core`. Import it and ship, or override any part of it with your own CSS. If your app already defines shadcn tokens, the theme picks up your colours and radius.
23
+ `@inkbar/theme` styles the viewer, toolbar controls and note threads from `@inkbar/vue`, `@inkbar/react`, `@inkbar/svelte` and `createViewer` in `@inkbar/core`. Import it and ship, or override any part of it with your own CSS. If your app already defines shadcn tokens, the theme picks up your colours and radius.
24
24
 
25
25
  ## Install
26
26
 
@@ -60,13 +60,12 @@ Colour tokens must hold complete CSS colour values. Tokens written as bare HSL c
60
60
 
61
61
  Set these variables on `[data-ink-root]` to change the default colour for new annotations:
62
62
 
63
- | Variable | Used for |
64
- | -------------------------------------------------------------------------- | ----------------------------------- |
65
- | `--ink-highlight`, `--ink-underline`, `--ink-strikeout`, `--ink-squiggly` | Text markup |
66
- | `--ink-note`, `--ink-free-text` | Notes and text boxes |
67
- | `--ink-shape`, `--ink-ink` | Shapes and freehand drawing |
68
- | `--ink-redact`, `--ink-redact-fill` | Redaction outline and fill |
69
- | `--ink-suggestion-low`, `--ink-suggestion-medium`, `--ink-suggestion-high` | Suggested redactions, by confidence |
63
+ | Variable | Used for |
64
+ | ------------------------------------------------------------------------- | --------------------------- |
65
+ | `--ink-highlight`, `--ink-underline`, `--ink-strikeout`, `--ink-squiggly` | Text markup |
66
+ | `--ink-note`, `--ink-free-text` | Notes and text boxes |
67
+ | `--ink-shape`, `--ink-ink` | Shapes and freehand drawing |
68
+ | `--ink-redact`, `--ink-redact-fill` | Redaction outline and fill |
70
69
 
71
70
  Inkbar reads a colour when you create the annotation and stores it on the annotation, because the colour goes into the PDF. Changing a variable later affects new annotations only.
72
71
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkbar/theme",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Default stylesheet for Inkbar. Zero specificity, so your CSS wins.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://inkbar.dev",
package/theme.css CHANGED
@@ -14,9 +14,10 @@
14
14
  /* Tokens. Popovers are portalled out of the root, so they carry the tokens too. */
15
15
  :where(
16
16
  [data-ink-root],
17
- [data-ink-note-popover],
18
- [data-ink-suggestion-card],
19
- [data-ink-select-content]
17
+ [data-ink-thread-popover],
18
+ [data-ink-popover],
19
+ [data-ink-select-content],
20
+ [data-ink-signature-dialog]
20
21
  ) {
21
22
  --ink-highlight: #f2c230;
22
23
  --ink-underline: #2b5a9e;
@@ -28,9 +29,6 @@
28
29
  --ink-ink: #151820;
29
30
  --ink-redact: #c0392b;
30
31
  --ink-redact-fill: #000000;
31
- --ink-suggestion-low: #d4a017;
32
- --ink-suggestion-medium: #e67e22;
33
- --ink-suggestion-high: #c0392b;
34
32
 
35
33
  --ink-bg: var(--muted, #f1f2f5);
36
34
  --ink-fg: var(--foreground, #151820);
@@ -50,9 +48,10 @@
50
48
  @media (prefers-color-scheme: dark) {
51
49
  :where(
52
50
  [data-ink-root]:not(.light, .light *),
53
- [data-ink-note-popover]:not(.light *),
54
- [data-ink-suggestion-card]:not(.light *),
55
- [data-ink-select-content]:not(.light *)
51
+ [data-ink-thread-popover]:not(.light *),
52
+ [data-ink-popover]:not(.light *),
53
+ [data-ink-select-content]:not(.light *),
54
+ [data-ink-signature-dialog]:not(.light *)
56
55
  ) {
57
56
  --ink-bg: var(--muted, #0f1217);
58
57
  --ink-fg: var(--foreground, #e6e9ef);
@@ -70,9 +69,10 @@
70
69
  :where(
71
70
  .dark [data-ink-root]:not(.light, .dark .light *),
72
71
  [data-ink-root].dark,
73
- .dark [data-ink-note-popover]:not(.dark .light *),
74
- .dark [data-ink-suggestion-card]:not(.dark .light *),
75
- .dark [data-ink-select-content]:not(.dark .light *)
72
+ .dark [data-ink-thread-popover]:not(.dark .light *),
73
+ .dark [data-ink-popover]:not(.dark .light *),
74
+ .dark [data-ink-select-content]:not(.dark .light *),
75
+ .dark [data-ink-signature-dialog]:not(.dark .light *)
76
76
  ) {
77
77
  --ink-bg: var(--muted, #0f1217);
78
78
  --ink-fg: var(--foreground, #e6e9ef);
@@ -241,10 +241,11 @@
241
241
  background: transparent;
242
242
  }
243
243
 
244
- /* Tools: the active tool's cursor is set on the root; text spans follow it unless text is the target. */
244
+ /* Tools: the active tool's cursor is set on the root; page text follows it, except under
245
+ select text, where text is the target. */
245
246
  :where(
246
- [data-ink-tool='redact-area'] .ink-text-layer span,
247
- [data-ink-tool='note'] .ink-text-layer span
247
+ [data-ink-tool]:not([data-ink-tool='select-text']) .ink-text-layer span,
248
+ [data-ink-tool]:not([data-ink-tool='select-text']) .ink-text-layer br
248
249
  ) {
249
250
  cursor: inherit;
250
251
  }
@@ -259,7 +260,26 @@
259
260
  background: color-mix(in srgb, var(--ink-redact) 15%, transparent);
260
261
  }
261
262
 
262
- /* Resize handles on a selected area mark, text box or shape: shown with the select tool only. */
263
+ /* The shape draft's box is only its bounds; the outline is the SVG inside it. */
264
+ :where(.ink-draft[data-ink-draft='shape']) {
265
+ border: 0;
266
+ background: none;
267
+ }
268
+
269
+ :where(.ink-draft[data-ink-draft='shape'] svg) {
270
+ display: block;
271
+ stroke: var(--ink-accent);
272
+ stroke-width: 1.5;
273
+ stroke-dasharray: 4 3;
274
+ fill: color-mix(in srgb, var(--ink-accent) 10%, transparent);
275
+ }
276
+
277
+ :where(.ink-draft[data-ink-draft='shape'] polyline) {
278
+ fill: none;
279
+ }
280
+
281
+ /* Edit handles on a selected annotation: shown with the select tools, and on what a creation
282
+ tool just made (`data-ink-made`). */
263
283
  :where(.ink-handle) {
264
284
  box-sizing: border-box;
265
285
  border: 1px solid var(--ink-accent);
@@ -267,7 +287,14 @@
267
287
  background: var(--ink-surface);
268
288
  }
269
289
 
270
- :where([data-ink-tool]:not([data-ink-tool='select']) .ink-handle) {
290
+ :where(
291
+ [data-ink-tool]:not(
292
+ [data-ink-tool='select'],
293
+ [data-ink-tool='select-text'],
294
+ [data-ink-made]
295
+ )
296
+ .ink-handle
297
+ ) {
271
298
  display: none;
272
299
  }
273
300
 
@@ -279,6 +306,18 @@
279
306
  cursor: nesw-resize;
280
307
  }
281
308
 
309
+ :where(
310
+ .ink-handle[data-handle='start'],
311
+ .ink-handle[data-handle='end'],
312
+ .ink-handle[data-handle='callout']
313
+ ) {
314
+ cursor: crosshair;
315
+ }
316
+
317
+ :where(.ink-handle[data-handle='start'], .ink-handle[data-handle='end']) {
318
+ border-radius: 50%;
319
+ }
320
+
282
321
  /* Annotations */
283
322
  :where(.ink-overlay) {
284
323
  z-index: 1;
@@ -290,17 +329,56 @@
290
329
  outline-offset: 1px;
291
330
  }
292
331
 
332
+ /* An annotation's SVGs (its shape, and a text box's edge band over the text) cover its box. */
293
333
  :where(.ink-annotation:not([data-custom]) > svg) {
294
334
  position: absolute;
295
335
  left: 0;
296
336
  top: 0;
297
337
  }
298
338
 
339
+ /* Cursors say what a press will do: move an annotation, edit a text box's text, or (text
340
+ markup under select text) select text. Under rectangle select a press on text markup
341
+ selects and drags it, so it shows move there. The creation tools' cursor shows through
342
+ elsewhere. */
299
343
  :where(
300
344
  [data-ink-tool='select'] .ink-annotation,
301
- [data-ink-tool='view'] .ink-annotation
345
+ [data-ink-tool='select-text'] .ink-annotation,
346
+ [data-ink-made] .ink-annotation[data-state='selected']
302
347
  ) {
303
- cursor: pointer;
348
+ cursor: move;
349
+ }
350
+
351
+ :where(
352
+ [data-ink-tool='select-text']
353
+ .ink-annotation:is(
354
+ [data-type='highlight'],
355
+ [data-type='underline'],
356
+ [data-type='strikeout'],
357
+ [data-type='squiggly']
358
+ )
359
+ ) {
360
+ cursor: text;
361
+ }
362
+
363
+ :where(
364
+ [data-ink-tool='select'] .ink-annotation:not([data-locked]) .ink-free-text,
365
+ [data-ink-tool='select-text'] .ink-annotation:not([data-locked]) .ink-free-text,
366
+ [data-ink-made]
367
+ .ink-annotation[data-state='selected']:not([data-locked])
368
+ .ink-free-text
369
+ ) {
370
+ cursor: text;
371
+ }
372
+
373
+ /* The band along a text box's edge presses to move it, not to edit. */
374
+ :where(
375
+ [data-ink-tool='select'] .ink-annotation:not([data-locked]) [data-ink-edge],
376
+ [data-ink-tool='select-text'] .ink-annotation:not([data-locked]) [data-ink-edge],
377
+ [data-ink-made]
378
+ .ink-annotation[data-state='selected']:not([data-locked])
379
+ [data-ink-edge]
380
+ ) {
381
+ cursor: move;
304
382
  }
305
383
 
306
384
  :where(.ink-annotation[data-state='hover']) {
@@ -316,12 +394,45 @@
316
394
  cursor: default;
317
395
  }
318
396
 
397
+ /* While an annotation is moved the whole viewport shows it, over any element's own cursor.
398
+ The one rule here that is not zero specificity: it has to beat them. */
399
+ [data-ink-dragging],
400
+ [data-ink-dragging] * {
401
+ cursor: move !important;
402
+ }
403
+
319
404
  :where(.ink-annotation[data-locked][data-state='selected']) {
320
405
  outline-style: dotted;
321
406
  }
322
407
 
323
- :where(.ink-annotation[data-origin='suggested'] .ink-annotation-shape > *) {
324
- stroke-dasharray: 4 3;
408
+ /* A free text inset by a fringe outlines its text box, where its corner handles sit, not
409
+ the whole rect with its callout. */
410
+ :where(.ink-annotation[data-framed]) {
411
+ outline-color: transparent;
412
+ }
413
+
414
+ :where(.ink-selection-frame) {
415
+ border-radius: 2px;
416
+ outline: 1px solid transparent;
417
+ outline-offset: 1px;
418
+ }
419
+
420
+ :where(.ink-annotation[data-framed][data-state='hover'] > .ink-selection-frame) {
421
+ outline-color: color-mix(in srgb, var(--ink-ring) 50%, transparent);
422
+ }
423
+
424
+ :where(
425
+ .ink-annotation[data-framed][data-state='selected'] > .ink-selection-frame,
426
+ .ink-annotation[data-framed]:focus-visible > .ink-selection-frame
427
+ ) {
428
+ outline: 2px solid var(--ink-ring);
429
+ }
430
+
431
+ :where(
432
+ .ink-annotation[data-framed][data-locked][data-state='selected']
433
+ > .ink-selection-frame
434
+ ) {
435
+ outline-style: dotted;
325
436
  }
326
437
 
327
438
  :where(.ink-note-icon) {
@@ -337,19 +448,58 @@
337
448
  pointer-events: none;
338
449
  }
339
450
 
451
+ /* Commented text markup: a comment glyph at the markup's end. */
452
+ :where(.ink-comment-marker) {
453
+ position: absolute;
454
+ display: grid;
455
+ place-items: center;
456
+ width: 14px;
457
+ height: 14px;
458
+ translate: -25% -75%;
459
+ border-radius: 4px;
460
+ background: var(--ink-surface);
461
+ color: var(--ink-accent);
462
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.3);
463
+ pointer-events: none;
464
+ }
465
+
466
+ :where(.ink-comment-marker > svg) {
467
+ width: 10px;
468
+ height: 10px;
469
+ }
470
+
340
471
  :where(.ink-free-text) {
472
+ box-sizing: border-box;
341
473
  width: 100%;
342
474
  height: 100%;
343
475
  overflow: hidden;
344
476
  font-family: var(--ink-font-family, Helvetica), Helvetica, Arial, sans-serif;
345
477
  font-size: var(--ink-font-size);
478
+ font-weight: var(--ink-font-weight, normal);
479
+ font-style: var(--ink-font-style, normal);
480
+ text-decoration: var(--ink-text-decoration, none);
346
481
  line-height: 1.2;
347
482
  color: var(--ink-text-color, var(--ink-free-text));
483
+ background: var(--ink-fill, transparent);
484
+ border-radius: var(--ink-corner-radius, 0);
348
485
  opacity: var(--ink-opacity, 1);
349
486
  overflow-wrap: break-word;
350
487
  white-space: pre-wrap;
351
488
  }
352
489
 
490
+ :where(.ink-free-text[data-border]) {
491
+ border: var(--ink-border-width, 1px) solid var(--ink-box-border, var(--ink-free-text));
492
+ }
493
+
494
+ :where(.ink-free-text[data-border='dashed']) {
495
+ border-style: dashed;
496
+ }
497
+
498
+ /* A speech bubble's outline is the path beside the text, so the text only needs room inside it. */
499
+ :where(.ink-free-text[data-bubble]) {
500
+ padding: 0.4em 0.6em;
501
+ }
502
+
353
503
  :where(.ink-free-text[data-align='left']) {
354
504
  text-align: left;
355
505
  }
@@ -362,6 +512,19 @@
362
512
  text-align: right;
363
513
  }
364
514
 
515
+ :where(.ink-free-text[data-align='justify']) {
516
+ text-align: justify;
517
+ }
518
+
519
+ /* The in-place editor grows with its text, and shows where the box is while it is empty. */
520
+ :where(.ink-free-text[data-ink-editor]) {
521
+ height: auto;
522
+ overflow: visible;
523
+ outline: 1px dashed var(--ink-free-text);
524
+ outline-offset: 1px;
525
+ cursor: text;
526
+ }
527
+
365
528
  /*
366
529
  * Toolbar. The theme styles the bar's surface and the controls in it; where a bar sits, how
367
530
  * its controls are grouped and what separates it from the document are up to the app.
@@ -572,8 +735,558 @@
572
735
  display: inline-flex;
573
736
  }
574
737
 
575
- /* Note threads and suggestion cards */
576
- :where(.ink-note-popover, .ink-suggestion-card) {
738
+ /*
739
+ * Style menus (line style and the other style controls). The panel takes the select
740
+ * panel's box through `.ink-select-content`; its items are buttons.
741
+ */
742
+ :where(.ink-menu-content) {
743
+ min-width: 11rem;
744
+ }
745
+
746
+ :where(.ink-menu-group + .ink-menu-group) {
747
+ margin-top: 0.25rem;
748
+ padding-top: 0.25rem;
749
+ border-top: 1px solid var(--ink-border);
750
+ }
751
+
752
+ :where(.ink-menu-label) {
753
+ padding: 0.25rem 0.5rem;
754
+ color: var(--ink-muted-fg);
755
+ font-size: 0.75rem;
756
+ }
757
+
758
+ :where(.ink-menu-item) {
759
+ box-sizing: border-box;
760
+ width: 100%;
761
+ border: 0;
762
+ background: none;
763
+ color: inherit;
764
+ font: inherit;
765
+ text-align: left;
766
+ }
767
+
768
+ :where(.ink-menu-item:hover:not(:disabled), .ink-menu-item:focus-visible) {
769
+ background: color-mix(in srgb, var(--ink-fg) 8%, transparent);
770
+ }
771
+
772
+ :where(.ink-menu-item:disabled) {
773
+ opacity: 0.5;
774
+ }
775
+
776
+ /*
777
+ * Colour menus. The trigger shows the current colour as a swatch; `data-kind` is `color`,
778
+ * `none` (slashed), `mixed` (split) or `empty`. A border swatch is a ring, a fill swatch a
779
+ * disc.
780
+ */
781
+ :where(.ink-swatch) {
782
+ position: relative;
783
+ display: inline-block;
784
+ box-sizing: border-box;
785
+ width: 1.125rem;
786
+ height: 1.125rem;
787
+ overflow: hidden;
788
+ border: 1px solid color-mix(in srgb, var(--ink-fg) 35%, transparent);
789
+ border-radius: 50%;
790
+ background: var(--ink-swatch, transparent);
791
+ }
792
+
793
+ :where(.ink-swatch[data-property='border'][data-kind='color']) {
794
+ border: 3px solid var(--ink-swatch);
795
+ background: transparent;
796
+ }
797
+
798
+ :where(.ink-swatch[data-kind='none'])::after {
799
+ content: '';
800
+ position: absolute;
801
+ inset: 0;
802
+ background: linear-gradient(
803
+ to top right,
804
+ transparent calc(50% - 1px),
805
+ #e5484d calc(50% - 1px),
806
+ #e5484d calc(50% + 1px),
807
+ transparent calc(50% + 1px)
808
+ );
809
+ }
810
+
811
+ :where(.ink-swatch[data-kind='mixed']) {
812
+ background: linear-gradient(135deg, #e5484d 50%, #3b82f6 50%);
813
+ }
814
+
815
+ :where(.ink-color-grid) {
816
+ display: grid;
817
+ grid-template-columns: repeat(12, 1.25rem);
818
+ gap: 2px;
819
+ padding: 0.25rem;
820
+ }
821
+
822
+ :where(.ink-swatch-item) {
823
+ box-sizing: border-box;
824
+ width: 1.25rem;
825
+ height: 1.25rem;
826
+ padding: 0;
827
+ border: 1px solid color-mix(in srgb, var(--ink-fg) 20%, transparent);
828
+ border-radius: 3px;
829
+ background: var(--ink-swatch);
830
+ cursor: default;
831
+ }
832
+
833
+ :where(.ink-swatch-item[data-state='checked']) {
834
+ outline: 2px solid var(--ink-fg);
835
+ outline-offset: 1px;
836
+ }
837
+
838
+ :where(.ink-swatch-item:hover, .ink-swatch-item:focus-visible) {
839
+ outline: 2px solid var(--ink-ring, var(--ink-fg));
840
+ outline-offset: 1px;
841
+ }
842
+
843
+ /* The native input stays in the page so its picker opens; only the picker is seen. */
844
+ :where(.ink-color-input) {
845
+ position: absolute;
846
+ width: 1px;
847
+ height: 1px;
848
+ padding: 0;
849
+ border: 0;
850
+ overflow: hidden;
851
+ clip-path: inset(50%);
852
+ opacity: 0;
853
+ pointer-events: none;
854
+ }
855
+
856
+ /*
857
+ * Text style menu: a popover panel of mixed widgets (font select, text colour, size stepper,
858
+ * emphasis toggles, alignment radios).
859
+ */
860
+ :where(.ink-text-style-content) {
861
+ display: flex;
862
+ flex-direction: column;
863
+ gap: 0.5rem;
864
+ padding: 0.5rem;
865
+ }
866
+
867
+ :where(.ink-text-style-row, .ink-text-style-size) {
868
+ display: flex;
869
+ align-items: center;
870
+ gap: 0.25rem;
871
+ }
872
+
873
+ :where(.ink-text-style-font, .ink-text-style-input) {
874
+ box-sizing: border-box;
875
+ height: 2rem;
876
+ padding: 0 0.5rem;
877
+ border: 1px solid var(--ink-border);
878
+ border-radius: calc(var(--ink-radius) - 2px);
879
+ background: var(--ink-surface);
880
+ color: inherit;
881
+ font: inherit;
882
+ }
883
+
884
+ :where(.ink-text-style-input) {
885
+ width: 3.5rem;
886
+ text-align: center;
887
+ appearance: textfield;
888
+ }
889
+
890
+ :where(.ink-text-style-button) {
891
+ display: inline-flex;
892
+ align-items: center;
893
+ justify-content: center;
894
+ box-sizing: border-box;
895
+ width: 2rem;
896
+ height: 2rem;
897
+ padding: 0;
898
+ border: 1px solid transparent;
899
+ border-radius: calc(var(--ink-radius) - 2px);
900
+ background: none;
901
+ color: inherit;
902
+ cursor: default;
903
+ }
904
+
905
+ :where(.ink-text-style-button:hover, .ink-text-style-button:focus-visible) {
906
+ background: color-mix(in srgb, var(--ink-fg) 8%, transparent);
907
+ }
908
+
909
+ :where(.ink-text-style-button[data-state='on']) {
910
+ border-color: var(--ink-border);
911
+ background: color-mix(in srgb, var(--ink-fg) 14%, transparent);
912
+ }
913
+
914
+ :where(.ink-text-style-button[data-mixed]) {
915
+ border-style: dashed;
916
+ border-color: var(--ink-border);
917
+ }
918
+
919
+ /* A style menu's trigger when the selection disagrees (the colour menus' swatch shows it too). */
920
+ :where(.ink-menu-trigger[data-mixed]) {
921
+ border-style: dashed;
922
+ border-color: var(--ink-border);
923
+ }
924
+
925
+ /*
926
+ * Split buttons (shape, highlight, signature): one control with two parts, the tool button
927
+ * beside a narrow chevron. Hovering either part tints the whole control and the part under
928
+ * the pointer a shade more; with the tool on, both parts take the accent. Plain sibling
929
+ * selectors, not :has(), which costs frames on long documents.
930
+ */
931
+ :where(.ink-split-button) {
932
+ display: inline-flex;
933
+ align-items: stretch;
934
+ border-radius: calc(var(--ink-radius) - 2px);
935
+ }
936
+
937
+ :where(.ink-split-button > .ink-tool-button) {
938
+ border-start-end-radius: 0;
939
+ border-end-end-radius: 0;
940
+ }
941
+
942
+ :where(.ink-split-button > .ink-menu-trigger) {
943
+ min-width: 0;
944
+ width: 1.25rem;
945
+ padding-inline: 0.125rem;
946
+ border-start-start-radius: 0;
947
+ border-end-start-radius: 0;
948
+ }
949
+
950
+ :where(.ink-split-button:hover) {
951
+ background: color-mix(in srgb, var(--ink-fg) 8%, transparent);
952
+ }
953
+
954
+ /* The tool button's on state already takes the accent; the chevron beside it follows. */
955
+ :where(.ink-split-button > .ink-tool-button[data-state='on'] + .ink-menu-trigger) {
956
+ background: var(--ink-accent);
957
+ color: var(--ink-accent-fg);
958
+ /* The line between the parts, only while the accent fills both. */
959
+ box-shadow: inset 1px 0 color-mix(in srgb, var(--ink-accent-fg) 35%, transparent);
960
+ }
961
+
962
+ :where(
963
+ .ink-split-button > .ink-tool-button[data-state='on']:hover,
964
+ .ink-split-button > .ink-tool-button[data-state='on'] + .ink-menu-trigger:hover
965
+ ) {
966
+ background: color-mix(in srgb, var(--ink-accent-fg) 16%, var(--ink-accent));
967
+ }
968
+
969
+ :where(.ink-shape-grid) {
970
+ display: grid;
971
+ grid-template-columns: repeat(2, minmax(8.5rem, 1fr));
972
+ gap: 2px;
973
+ padding: 0.25rem;
974
+ }
975
+
976
+ :where(.ink-shape-item) {
977
+ display: flex;
978
+ align-items: center;
979
+ gap: 0.5rem;
980
+ padding-right: 0.5rem;
981
+ }
982
+
983
+ /* Highlight menu: the markup kinds, then the markup colour. */
984
+ :where(.ink-highlight-kinds) {
985
+ display: grid;
986
+ gap: 2px;
987
+ padding: 0.25rem;
988
+ }
989
+
990
+ :where(.ink-highlight-item) {
991
+ display: flex;
992
+ align-items: center;
993
+ gap: 0.5rem;
994
+ padding-right: 0.5rem;
995
+ }
996
+
997
+ /*
998
+ * The colour row reads as one more item: the swatch sits in the icon column and "Colour" in
999
+ * the label column. The colour menu's trigger covers the whole row, so the row is the target;
1000
+ * the label shows through it.
1001
+ */
1002
+ :where(.ink-highlight-colour) {
1003
+ position: relative;
1004
+ display: flex;
1005
+ align-items: center;
1006
+ padding: 0.25rem;
1007
+ }
1008
+
1009
+ :where(.ink-highlight-colour-label) {
1010
+ padding: 0.375rem 0.5rem 0.375rem 2rem;
1011
+ }
1012
+
1013
+ :where(.ink-highlight-colour > .ink-menu-trigger) {
1014
+ position: absolute;
1015
+ inset: 0.25rem;
1016
+ display: flex;
1017
+ align-items: center;
1018
+ justify-content: flex-start;
1019
+ width: auto;
1020
+ min-width: 0;
1021
+ height: auto;
1022
+ padding: 0 0.5rem;
1023
+ border: 0;
1024
+ border-radius: calc(var(--ink-radius) - 4px);
1025
+ background: transparent;
1026
+ }
1027
+
1028
+ :where(
1029
+ .ink-highlight-colour > .ink-menu-trigger:hover,
1030
+ .ink-highlight-colour > .ink-menu-trigger:focus-visible,
1031
+ .ink-highlight-colour > .ink-menu-trigger[data-state='open']
1032
+ ) {
1033
+ background: color-mix(in srgb, var(--ink-fg) 8%, transparent);
1034
+ }
1035
+
1036
+ /* A markup colour is a fill, so its swatch is a disc, not the border ring. */
1037
+ :where(.ink-highlight-colour .ink-swatch) {
1038
+ width: 1rem;
1039
+ height: 1rem;
1040
+ }
1041
+
1042
+ :where(.ink-highlight-colour .ink-swatch[data-kind='color']) {
1043
+ border: 1px solid color-mix(in srgb, var(--ink-fg) 20%, transparent);
1044
+ background: var(--ink-swatch);
1045
+ }
1046
+
1047
+ /* Stamps: an image filling its box; the overlay sets its geometry and opacity. */
1048
+ :where(.ink-stamp) {
1049
+ display: block;
1050
+ max-width: none;
1051
+ opacity: var(--ink-opacity, 1);
1052
+ user-select: none;
1053
+ }
1054
+
1055
+ /* Signature menu: saved signatures as previews, each with a remove button. */
1056
+ :where(.ink-signature-list) {
1057
+ display: grid;
1058
+ grid-template-columns: minmax(10rem, 1fr) auto;
1059
+ gap: 2px;
1060
+ padding: 0.25rem;
1061
+ }
1062
+
1063
+ :where(.ink-signature-item) {
1064
+ padding-right: 0.5rem;
1065
+ color: var(--ink-ink);
1066
+ }
1067
+
1068
+ :where(.ink-signature-item[data-state='checked']) {
1069
+ background: color-mix(in srgb, var(--ink-accent) 10%, transparent);
1070
+ }
1071
+
1072
+ /* Signatures are dark ink in both themes, so they sit on paper. */
1073
+ :where(.ink-signature-preview) {
1074
+ display: inline-flex;
1075
+ align-items: center;
1076
+ height: 2rem;
1077
+ border-radius: calc(var(--ink-radius) - 4px);
1078
+ background: #fff;
1079
+ }
1080
+
1081
+ :where(.ink-signature-preview svg, .ink-signature-preview img) {
1082
+ height: 100%;
1083
+ max-width: 10rem;
1084
+ object-fit: contain;
1085
+ }
1086
+
1087
+ :where(.ink-signature-remove) {
1088
+ display: inline-flex;
1089
+ align-items: center;
1090
+ justify-content: center;
1091
+ width: 2rem;
1092
+ padding: 0;
1093
+ border-radius: calc(var(--ink-radius) - 4px);
1094
+ color: var(--ink-muted-fg);
1095
+ }
1096
+
1097
+ :where(.ink-signature-create) {
1098
+ display: flex;
1099
+ align-items: center;
1100
+ gap: 0.5rem;
1101
+ padding-right: 0.5rem;
1102
+ }
1103
+
1104
+ /* Dialogs (Create signature): a modal over an overlay. */
1105
+ :where(.ink-dialog-overlay) {
1106
+ position: fixed;
1107
+ inset: 0;
1108
+ z-index: 50;
1109
+ background: rgb(0 0 0 / 0.4);
1110
+ }
1111
+
1112
+ :where(.ink-dialog) {
1113
+ position: fixed;
1114
+ top: 50%;
1115
+ left: 50%;
1116
+ z-index: 51;
1117
+ box-sizing: border-box;
1118
+ width: min(32rem, calc(100vw - 2rem));
1119
+ max-height: calc(100vh - 2rem);
1120
+ overflow: auto;
1121
+ padding: 1rem;
1122
+ border: 1px solid var(--ink-border);
1123
+ border-radius: var(--ink-radius);
1124
+ background: var(--ink-surface);
1125
+ color: var(--ink-fg);
1126
+ box-shadow: 0 16px 48px rgb(0 0 0 / 0.25);
1127
+ font-size: 0.875rem;
1128
+ transform: translate(-50%, -50%);
1129
+ }
1130
+
1131
+ :where(.ink-dialog:focus) {
1132
+ outline: none;
1133
+ }
1134
+
1135
+ :where(.ink-dialog-title) {
1136
+ margin: 0 0 0.75rem;
1137
+ font-size: 1rem;
1138
+ font-weight: 600;
1139
+ }
1140
+
1141
+ :where(.ink-tabs) {
1142
+ display: flex;
1143
+ gap: 0.25rem;
1144
+ margin-bottom: 0.75rem;
1145
+ border-bottom: 1px solid var(--ink-border);
1146
+ }
1147
+
1148
+ :where(.ink-tab) {
1149
+ margin-bottom: -1px;
1150
+ padding: 0.375rem 0.75rem;
1151
+ border: 0;
1152
+ border-bottom: 2px solid transparent;
1153
+ background: none;
1154
+ color: var(--ink-muted-fg);
1155
+ font: inherit;
1156
+ cursor: pointer;
1157
+ }
1158
+
1159
+ :where(.ink-tab[data-state='active']) {
1160
+ border-bottom-color: var(--ink-accent);
1161
+ color: var(--ink-fg);
1162
+ }
1163
+
1164
+ :where(.ink-tab-panel) {
1165
+ display: grid;
1166
+ gap: 0.5rem;
1167
+ }
1168
+
1169
+ :where(.ink-tab-panel[hidden]) {
1170
+ display: none;
1171
+ }
1172
+
1173
+ :where(.ink-signature-pad-host) {
1174
+ box-sizing: border-box;
1175
+ height: 10rem;
1176
+ border: 1px dashed var(--ink-border);
1177
+ border-radius: calc(var(--ink-radius) - 2px);
1178
+ background: #fff;
1179
+ color: var(--ink-ink);
1180
+ cursor: crosshair;
1181
+ }
1182
+
1183
+ :where(.ink-signature-pad .ink-stroke) {
1184
+ fill: currentColor;
1185
+ }
1186
+
1187
+ :where(.ink-dialog-row) {
1188
+ display: flex;
1189
+ justify-content: flex-end;
1190
+ }
1191
+
1192
+ :where(.ink-field) {
1193
+ display: grid;
1194
+ gap: 0.25rem;
1195
+ }
1196
+
1197
+ :where(.ink-input) {
1198
+ box-sizing: border-box;
1199
+ width: 100%;
1200
+ padding: 0.375rem;
1201
+ border: 1px solid var(--ink-border);
1202
+ border-radius: calc(var(--ink-radius) - 2px);
1203
+ background: var(--ink-surface);
1204
+ color: inherit;
1205
+ font: inherit;
1206
+ }
1207
+
1208
+ :where(.ink-field-error) {
1209
+ margin: 0;
1210
+ color: var(--ink-strikeout);
1211
+ }
1212
+
1213
+ :where(.ink-signature-fonts) {
1214
+ display: grid;
1215
+ gap: 0.25rem;
1216
+ }
1217
+
1218
+ :where(.ink-signature-font) {
1219
+ overflow: hidden;
1220
+ padding: 0.25rem 0.5rem;
1221
+ border: 1px solid var(--ink-border);
1222
+ border-radius: calc(var(--ink-radius) - 2px);
1223
+ background: #fff;
1224
+ color: var(--ink-ink);
1225
+ text-align: left;
1226
+ text-overflow: ellipsis;
1227
+ white-space: nowrap;
1228
+ cursor: pointer;
1229
+ }
1230
+
1231
+ :where(.ink-signature-font-sample) {
1232
+ font-size: 1.75rem;
1233
+ line-height: 1.4;
1234
+ }
1235
+
1236
+ :where(.ink-signature-font[data-state='checked']) {
1237
+ border-color: var(--ink-accent);
1238
+ box-shadow: inset 0 0 0 1px var(--ink-accent);
1239
+ }
1240
+
1241
+ :where(.ink-signature-image) {
1242
+ max-width: 100%;
1243
+ max-height: 8rem;
1244
+ object-fit: contain;
1245
+ }
1246
+
1247
+ :where(.ink-dialog-actions) {
1248
+ display: flex;
1249
+ justify-content: flex-end;
1250
+ gap: 0.375rem;
1251
+ margin-top: 1rem;
1252
+ }
1253
+
1254
+ :where(.ink-button) {
1255
+ padding: 0.375rem 0.75rem;
1256
+ border: 1px solid var(--ink-border);
1257
+ border-radius: calc(var(--ink-radius) - 2px);
1258
+ background: var(--ink-surface);
1259
+ color: inherit;
1260
+ font: inherit;
1261
+ cursor: pointer;
1262
+ }
1263
+
1264
+ :where(.ink-button[data-variant='primary']) {
1265
+ border-color: var(--ink-accent);
1266
+ background: var(--ink-accent);
1267
+ color: var(--ink-accent-fg);
1268
+ }
1269
+
1270
+ :where(.ink-button:disabled) {
1271
+ opacity: 0.5;
1272
+ cursor: default;
1273
+ }
1274
+
1275
+ :where(
1276
+ .ink-tab:focus-visible,
1277
+ .ink-button:focus-visible,
1278
+ .ink-input:focus-visible,
1279
+ .ink-signature-font:focus-visible,
1280
+ .ink-text-style-font:focus-visible,
1281
+ .ink-text-style-input:focus-visible,
1282
+ .ink-text-style-button:focus-visible
1283
+ ) {
1284
+ outline: 2px solid var(--ink-ring);
1285
+ outline-offset: 2px;
1286
+ }
1287
+
1288
+ /* Comment threads */
1289
+ :where(.ink-thread-popover) {
577
1290
  z-index: 50;
578
1291
  width: 20rem;
579
1292
  max-width: calc(100vw - 1rem);
@@ -629,13 +1342,13 @@
629
1342
  resize: vertical;
630
1343
  }
631
1344
 
632
- :where(.ink-thread-actions, .ink-suggestion-actions) {
1345
+ :where(.ink-thread-actions) {
633
1346
  display: flex;
634
1347
  gap: 0.375rem;
635
1348
  margin-top: 0.5rem;
636
1349
  }
637
1350
 
638
- :where(.ink-thread-actions button, .ink-suggestion-actions button) {
1351
+ :where(.ink-thread-actions button) {
639
1352
  padding: 0.375rem 0.75rem;
640
1353
  border: 1px solid var(--ink-border);
641
1354
  border-radius: calc(var(--ink-radius) - 2px);
@@ -645,10 +1358,7 @@
645
1358
  cursor: pointer;
646
1359
  }
647
1360
 
648
- :where(
649
- .ink-thread-actions button[type='submit'],
650
- .ink-suggestion-actions button:first-child
651
- ) {
1361
+ :where(.ink-thread-actions button[type='submit']) {
652
1362
  border-color: var(--ink-accent);
653
1363
  background: var(--ink-accent);
654
1364
  color: var(--ink-accent-fg);
@@ -669,53 +1379,12 @@
669
1379
  .ink-select-trigger:focus-visible,
670
1380
  .ink-toolbar input:focus-visible,
671
1381
  .ink-thread-actions button:focus-visible,
672
- .ink-suggestion-actions button:focus-visible,
673
1382
  .ink-thread-reply textarea:focus-visible
674
1383
  ) {
675
1384
  outline: 2px solid var(--ink-ring);
676
1385
  outline-offset: 2px;
677
1386
  }
678
1387
 
679
- :where(.ink-suggestion-reason, .ink-suggestion-explanation) {
680
- margin: 0;
681
- }
682
-
683
- :where(.ink-suggestion-explanation) {
684
- margin-top: 0.25rem;
685
- color: var(--ink-muted-fg);
686
- }
687
-
688
- /* The label text keeps the body colour for contrast; the confidence colour is a swatch. */
689
- :where(.ink-suggestion-confidence) {
690
- display: inline-flex;
691
- align-items: center;
692
- gap: 0.375rem;
693
- margin-left: 0.5rem;
694
- color: var(--ink-fg);
695
- font-size: 0.75rem;
696
- text-transform: capitalize;
697
- }
698
-
699
- :where(.ink-suggestion-confidence)::before {
700
- content: '';
701
- width: 0.5rem;
702
- height: 0.5rem;
703
- border-radius: 50%;
704
- background: currentColor;
705
- }
706
-
707
- :where(.ink-suggestion-confidence[data-confidence='low'])::before {
708
- background: var(--ink-suggestion-low);
709
- }
710
-
711
- :where(.ink-suggestion-confidence[data-confidence='medium'])::before {
712
- background: var(--ink-suggestion-medium);
713
- }
714
-
715
- :where(.ink-suggestion-confidence[data-confidence='high'])::before {
716
- background: var(--ink-suggestion-high);
717
- }
718
-
719
1388
  @media (prefers-reduced-motion: no-preference) {
720
1389
  :where(.ink-annotation) {
721
1390
  transition: outline-color 120ms ease;