@puredesktop/puredesktop-ui-bridge 2.1.4 → 2.1.7

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 (183) hide show
  1. package/package.json +19 -1
  2. package/src/agents/runtime/mapAgentSnapshot.test.ts +1 -3
  3. package/src/agents/runtime/mapAgentSnapshot.ts +8 -4
  4. package/src/agents/runtime/mergeUsageTurn.ts +1 -2
  5. package/src/agents/runtime/pendingToolCalls.test.ts +1 -3
  6. package/src/agents/runtime/unresolvedToolCalls.ts +1 -2
  7. package/src/bridge/agentModelTiers.ts +9 -4
  8. package/src/bridge/agents.mjs +3 -1
  9. package/src/bridge/calendarDraftIntent.ts +12 -4
  10. package/src/bridge/calendarInviteIntent.ts +18 -5
  11. package/src/bridge/client.mjs +45 -45
  12. package/src/bridge/dialog.d.mts +8 -8
  13. package/src/bridge/dialog.mjs +40 -40
  14. package/src/bridge/dialog.test.ts +73 -73
  15. package/src/bridge/fs.d.mts +41 -41
  16. package/src/bridge/fs.mjs +56 -56
  17. package/src/bridge/fs.test.ts +83 -83
  18. package/src/bridge/fs.ts +28 -28
  19. package/src/bridge/googleAuth.ts +3 -1
  20. package/src/bridge/methods.d.mts +6 -0
  21. package/src/bridge/methods.mjs +7 -0
  22. package/src/bridge/network.d.mts +17 -17
  23. package/src/bridge/network.mjs +22 -22
  24. package/src/bridge/pureRender/base.css +324 -76
  25. package/src/bridge/pureRender/compiler.ts +1 -1
  26. package/src/bridge/pureRender/document.test.ts +2 -2
  27. package/src/bridge/pureRender/extraction.test.ts +24 -12
  28. package/src/bridge/pureRender/extraction.ts +10 -7
  29. package/src/bridge/pureRender/flow.css +17 -3
  30. package/src/bridge/pureRender/normalize.ts +28 -26
  31. package/src/bridge/pureRender/presets.ts +7 -7
  32. package/src/bridge/pureRender/profiles/book.css +122 -19
  33. package/src/bridge/pureRender/profiles/manuscript.css +57 -11
  34. package/src/bridge/pureRender/profiles/writer.css +48 -10
  35. package/src/bridge/pureRender/reset.css +20 -5
  36. package/src/bridge/pureRender/theme.ts +37 -9
  37. package/src/bridge/pureRender/tokens/default.css +45 -33
  38. package/src/bridge/react/usePlatformAgentRunLiveState.tsx +4 -1
  39. package/src/bridge/react/usePlatformAgentSessionDrive.tsx +13 -4
  40. package/src/bridge/screenAnnotation.test.ts +4 -1
  41. package/src/bridge/screenAnnotation.ts +6 -2
  42. package/src/bridge/storage.d.mts +26 -24
  43. package/src/bridge/storage.mjs +18 -18
  44. package/src/bridge/storage.test.ts +45 -45
  45. package/src/bridge/types.ts +62 -58
  46. package/src/bridge/window.d.mts +3 -1
  47. package/src/bridge/workspace.d.mts +7 -0
  48. package/src/bridge/workspace.mjs +8 -0
  49. package/src/bridge/workspace.ts +1 -0
  50. package/src/commitments/commitments.test.ts +10 -3
  51. package/src/commitments/commitments.ts +18 -4
  52. package/src/components/accessibility/AccessibilityReviewDialog.tsx +7 -2
  53. package/src/components/accessibility/accessibilityReview.test.ts +11 -4
  54. package/src/components/accessibility/accessibilityReview.ts +18 -10
  55. package/src/components/agent-feedback/ScreenAnnotationAgentDialog.tsx +9 -2
  56. package/src/components/agents/AgentContextUsageBar.tsx +5 -3
  57. package/src/components/agents/AgentDrawerPanel.test.tsx +15 -3
  58. package/src/components/agents/AgentMessageBubble.tsx +1 -3
  59. package/src/components/agents/AgentQuestionPromptList.tsx +3 -3
  60. package/src/components/agents/AgentToolApprovalActions.tsx +1 -3
  61. package/src/components/agents/agentPanelStyles.ts +1 -3
  62. package/src/components/agents/agentToolDisplay.ts +4 -1
  63. package/src/components/assets/asset-library/AssetLibraryDialog.tsx +2 -0
  64. package/src/components/assets/asset-library/AssetLibraryWorkspace.tsx +2 -0
  65. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.test.tsx +40 -0
  66. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.tsx +7 -3
  67. package/src/components/assets/asset-library/detail/AssetLibraryDetailPreview.tsx +8 -8
  68. package/src/components/assets/asset-library/hooks/useAssetLibraryDialog.ts +13 -2
  69. package/src/components/assets/asset-library/hooks/useAssetLibraryMutations.ts +18 -1
  70. package/src/components/assets/asset-library/sidebar/AssetLibraryListRow.tsx +9 -6
  71. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarToolbar.tsx +3 -1
  72. package/src/components/assets/asset-library/sidebar/AssetListThumbnail.tsx +1 -1
  73. package/src/components/assets/asset-library/types.ts +6 -0
  74. package/src/components/chrome/OverlayActionCapsule.tsx +2 -2
  75. package/src/components/chrome/PanelTabStrip.tsx +3 -2
  76. package/src/components/chrome/PureAppWordmark.tsx +15 -15
  77. package/src/components/chrome/WorkspaceTabStrip.tsx +19 -14
  78. package/src/components/chrome/documentChromePolicy.test.ts +34 -0
  79. package/src/components/chrome/documentChromePolicy.ts +15 -0
  80. package/src/components/chrome/index.ts +4 -0
  81. package/src/components/chrome/workspaceTabTypes.ts +2 -0
  82. package/src/components/common/buttons/Button.tsx +60 -10
  83. package/src/components/common/buttons/ChoiceChip.tsx +2 -2
  84. package/src/components/common/buttons/IconButton.tsx +26 -0
  85. package/src/components/common/buttons/SegmentedControl.tsx +23 -7
  86. package/src/components/common/canvas/CanvasElementFrame.tsx +37 -28
  87. package/src/components/common/canvas/canvasGeometry.test.ts +4 -5
  88. package/src/components/common/canvas/canvasGeometry.ts +1 -4
  89. package/src/components/common/canvas/useCanvasDragResize.test.tsx +10 -10
  90. package/src/components/common/canvas/useCanvasDragResize.ts +1 -4
  91. package/src/components/common/cards/OpenReviewCard.tsx +6 -6
  92. package/src/components/common/chat/ChatBox.test.tsx +9 -1
  93. package/src/components/common/chat/ChatBox.tsx +3 -4
  94. package/src/components/common/chat/ChatMarkdown.tsx +1 -1
  95. package/src/components/common/chat/ChatModelMenu.tsx +1 -1
  96. package/src/components/common/chat/ChatThinkingIndicator.tsx +1 -1
  97. package/src/components/common/chat/ChatThread.tsx +2 -1
  98. package/src/components/common/chat/ChatToolRow.tsx +2 -2
  99. package/src/components/common/chat/ChatUserBubble.tsx +1 -1
  100. package/src/components/common/connections/ConnectionSetup.tsx +6 -6
  101. package/src/components/common/containers/AppFrame.test.tsx +37 -36
  102. package/src/components/common/containers/AppFrame.tsx +15 -0
  103. package/src/components/common/containers/AppHeader.tsx +6 -3
  104. package/src/components/common/containers/SurfacePanel.tsx +1 -0
  105. package/src/components/common/containers/useOpacityPresence.ts +10 -15
  106. package/src/components/common/context/ContextSelector.tsx +10 -10
  107. package/src/components/common/desk/CreationDesk.tsx +23 -11
  108. package/src/components/common/desk/DailyBrief.tsx +18 -7
  109. package/src/components/common/desk/DeskCard.tsx +11 -6
  110. package/src/components/common/dropdown/MenuButtonDropdown.tsx +58 -6
  111. package/src/components/common/dropdown/MenuDropdownItem.tsx +23 -3
  112. package/src/components/common/dropdown/MenuPanel.tsx +8 -8
  113. package/src/components/common/dropdown/SelectMenu.tsx +8 -3
  114. package/src/components/common/dropdown/menuTypes.ts +2 -1
  115. package/src/components/common/evidence/StructuredEvidenceView.tsx +9 -5
  116. package/src/components/common/feedback/Badge.tsx +19 -5
  117. package/src/components/common/feedback/CapabilityPills.tsx +1 -1
  118. package/src/components/common/feedback/InfoHint.tsx +2 -2
  119. package/src/components/common/feedback/PlatformChip.tsx +9 -9
  120. package/src/components/common/feedback/QuietPill.tsx +5 -8
  121. package/src/components/common/feedback/WorkProgressPanel.tsx +14 -14
  122. package/src/components/common/files/FileTable.tsx +8 -2
  123. package/src/components/common/inputs/Checkbox.tsx +1 -1
  124. package/src/components/common/inputs/EditableSecretField.tsx +1 -3
  125. package/src/components/common/inputs/InlineComposer.tsx +2 -2
  126. package/src/components/common/inputs/PaletteDropdown.tsx +33 -23
  127. package/src/components/common/inputs/SurfacePalettePicker.tsx +1 -1
  128. package/src/components/common/inputs/ToggleSwitch.tsx +2 -2
  129. package/src/components/common/inputs/WorkspacePicker.tsx +3 -3
  130. package/src/components/common/lists/listRowStyles.ts +4 -2
  131. package/src/components/common/lists/quiet-ledger/index.ts +1 -4
  132. package/src/components/common/lists/reorderable/DragHandle.tsx +1 -1
  133. package/src/components/common/lists/reorderable/ReorderableSections.tsx +2 -1
  134. package/src/components/common/media/ImageReferencePicker.tsx +22 -14
  135. package/src/components/common/narrative/NarrativeMention.tsx +15 -9
  136. package/src/components/common/navigation/NavigationCardRow.tsx +2 -2
  137. package/src/components/common/navigation/UnderlineTabs.tsx +1 -0
  138. package/src/components/common/overlays/Modal.tsx +52 -3
  139. package/src/components/common/overlays/ObjectActionStrip.tsx +2 -2
  140. package/src/components/common/people/AutoUpdateReviewList.tsx +2 -2
  141. package/src/components/common/people/EntityList.tsx +7 -3
  142. package/src/components/common/people/EntityPortrait.tsx +6 -1
  143. package/src/components/common/people/LinkedDossierList.tsx +3 -1
  144. package/src/components/common/people/RelationshipMap.tsx +3 -9
  145. package/src/components/common/research/EvidenceDossier.tsx +24 -20
  146. package/src/components/common/tiles/CatalogCard.tsx +1 -1
  147. package/src/components/credentials/CredentialsPanel.tsx +2 -6
  148. package/src/components/data/DataChart.tsx +119 -94
  149. package/src/components/data/dataTable.ts +4 -1
  150. package/src/components/editor/DocumentAppChrome.tsx +172 -0
  151. package/src/components/editor/EditorCommentPromptDialog.tsx +1 -1
  152. package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
  153. package/src/components/print-design/PrintDesignPanel.test.tsx +8 -6
  154. package/src/components/print-design/PrintDesignPanel.tsx +18 -25
  155. package/src/components/proofing/PagedProofDialog.tsx +17 -4
  156. package/src/editor/EditorViewModeToggle.tsx +6 -2
  157. package/src/editor/index.ts +6 -0
  158. package/src/theme/ThemeProvider.tsx +5 -2
  159. package/src/theme/appAccents.test.ts +51 -0
  160. package/src/theme/appAccents.ts +151 -88
  161. package/src/theme/appIdentityCss.mjs +256 -0
  162. package/src/theme/appIdentityCss.ts +256 -0
  163. package/src/theme/composePlatformTheme.test.ts +43 -14
  164. package/src/theme/platformFont.d.mts +2 -2
  165. package/src/theme/platformFont.mjs +4 -3
  166. package/src/theme/reportsShellChromeSelectors.ts +14 -132
  167. package/src/theme/surfaceCss.mjs +37 -0
  168. package/src/theme/surfaceCss.ts +37 -0
  169. package/src/theme/surfacePalettes.ts +120 -79
  170. package/src/theme/surfaceRoleSelectors.ts +135 -71
  171. package/src/theme/themes/dark.ts +44 -43
  172. package/src/theme/themes/light.ts +40 -38
  173. package/src/theme/themes/palette.ts +32 -30
  174. package/src/theme/themes/shared.ts +17 -17
  175. package/src/theme/utils/GlobalStyles.ts +10 -6
  176. package/src/theme/utils/appFrameDocumentStyles.mjs +6 -1
  177. package/src/theme/utils/cssVariables.ts +169 -0
  178. package/src/writing/DraftAssistantDialog.tsx +85 -85
  179. package/src/writing/WritingStyleManager.tsx +6 -3
  180. package/src/writing/draftTextWithAgent.ts +47 -50
  181. package/src/writing/styleStore.ts +4 -3
  182. package/src/writing/writingStyle.test.ts +8 -2
  183. package/src/writing/writingStyle.ts +19 -8
@@ -1,76 +1,324 @@
1
- html{ font-size:12pt; }
2
- body{
3
- color:var(--ink); background:var(--paper);
4
- font:var(--body)/var(--lead) var(--serif);
5
- font-variant-numeric:oldstyle-nums proportional-nums;
6
- -webkit-font-smoothing:antialiased;
7
- hyphens:var(--hyphenate);
8
- counter-reset:sec fig tbl ref eq;
9
- }
10
- .doc-title{ font:700 var(--t-title)/1.1 var(--display); margin:0 0 var(--rhythm); max-width:30rem; string-set:doctitle content(text); }
11
- .authors{ font:500 11.5pt/1.4 var(--sans); margin:0 0 .4rem; }
12
- .affil{ font:400 9pt/1.4 var(--sans); color:var(--muted); margin:0 0 calc(var(--rhythm)*1.2); }
13
- .affil sup,.authors sup{ font-size:.7em; }
14
- section[data-type="abstract"]{
15
- border-top:2px solid var(--accent); border-bottom:1px solid var(--rule);
16
- padding:calc(var(--rhythm)*.75) 0; margin:0 0 calc(var(--rhythm)*1.3); max-width:var(--measure);
17
- }
18
- section[data-type="abstract"] > h2{ all:unset; display:block; font:600 8pt/1 var(--sans); letter-spacing:.12em; text-transform:uppercase; color:var(--accent); margin:0 0 .5rem; counter-increment:none; }
19
- section[data-type="abstract"] > h2::before{ content:none; }
20
- section[data-type="abstract"] p{ margin:0; font-size:9.8pt; text-indent:0; }
21
- .keywords{ font:400 8.6pt/1.4 var(--sans); color:var(--muted); margin:.6rem 0 var(--rhythm); }
22
- .keywords b{ color:var(--ink-soft); font-weight:600; }
23
- section,p,ul,ol,blockquote{ max-width:var(--measure); }
24
- h2,h3,h4{ font-family:var(--display); color:var(--ink); break-after:avoid-page; }
25
- h2{ font-size:var(--t-h2); font-weight:700; line-height:1.15; margin:calc(var(--rhythm)*1.5) 0 calc(var(--rhythm)*.4); string-set:sectitle content(text); }
26
- section:not([data-type="abstract"]):not([data-type="frontmatter"]):not([data-type="backmatter"]):not([data-type="toc"]):not([data-type="references"]):not([data-type="endnotes"]):not([data-type="acknowledgments"]):not([data-type="part"]){ counter-increment:sec; counter-reset:sub; }
27
- h2::before{ content:counter(sec) "\00a0\00a0"; color:var(--accent); }
28
- section[data-type="abstract"] > h2::before,
29
- section[data-type="frontmatter"] > h2::before,
30
- section[data-type="backmatter"] > h2::before,
31
- section[data-type="toc"] > h2::before,
32
- section[data-type="references"] > h2::before,
33
- section[data-type="endnotes"] > h2::before,
34
- section[data-type="acknowledgments"] > h2::before,
35
- section[data-type="part"] > h2::before{ content:none; }
36
- h3{ counter-increment:sub; font-size:var(--t-h3); font-weight:600; margin:calc(var(--rhythm)*1) 0 calc(var(--rhythm)*.25); }
37
- h3::before{ content:counter(sec) "." counter(sub) "\00a0\00a0"; color:var(--accent); font-weight:500; }
38
- h4{ font-size:calc(var(--t-h3)*.88); font-weight:600; margin:calc(var(--rhythm)*.8) 0 calc(var(--rhythm)*.2); color:var(--ink-soft); }
39
- p{ margin:0; text-align:var(--text-align); orphans:3; widows:3; }
40
- p + p{ text-indent:1.25em; }
41
- h2 + p,h3 + p,section[data-type="abstract"] + p,figure + p{ text-indent:0; }
42
- a{ color:var(--accent-ink); text-decoration:none; }
43
- cite.ps-citation{ font-style:normal; white-space:nowrap; color:var(--accent-ink); }
44
- ul,ol{ margin:var(--rhythm) 0; padding-left:1.4rem; }
45
- li{ margin:.15rem 0; }
46
- figure{ counter-increment:fig; break-inside:avoid; margin:calc(var(--rhythm)*1.2) 0; }
47
- figcaption{ font:400 8.8pt/1.4 var(--serif); color:var(--ink-soft); margin-top:.55rem; max-width:var(--measure); }
48
- figcaption::before{ content:"Figure " attr(data-label) ".\00a0"; font-family:var(--sans); font-weight:var(--caption-label-weight); text-transform:var(--caption-label-transform); color:var(--ink); }
49
- .table-wrap{ counter-increment:tbl; break-inside:avoid; margin:calc(var(--rhythm)*1.2) 0; }
50
- .table-wrap > .tcaption{ font:400 8.8pt/1.4 var(--serif); color:var(--ink-soft); margin:0 0 .45rem; }
51
- .table-wrap > .tcaption::before{ content:"Table " attr(data-label) ".\00a0"; font-family:var(--sans); font-weight:var(--caption-label-weight); text-transform:var(--caption-label-transform); color:var(--ink); }
52
- table{ width:100%; font:400 9pt/1.35 var(--serif); }
53
- thead th{ font-family:var(--sans); font-weight:600; font-size:8.4pt; text-transform:var(--table-header-transform); letter-spacing:var(--table-header-letter-spacing); text-align:left; padding:var(--table-cell-padding-y) var(--table-cell-padding-x); color:var(--table-header-ink); background:var(--table-header-bg); border-bottom:var(--table-rule-width) solid var(--table-header-rule-color); }
54
- tbody td{ padding:var(--table-cell-padding-y) var(--table-cell-padding-x); border-bottom:var(--table-row-rule-width) solid var(--table-row-rule-color); }
55
- tbody tr:last-child td{ border-bottom:var(--table-rule-width) solid var(--rule); }
56
- .num{ text-align:right; font-variant-numeric:tabular-nums; }
57
- .equation{ counter-increment:eq; display:flex; align-items:center; gap:1rem; justify-content:center; margin:calc(var(--rhythm)*1) 0; break-inside:avoid; }
58
- .equation .eq-body{ font:italic 400 12pt/1 var(--serif); }
59
- .equation .eq-num{ margin-left:auto; }
60
- .equation .eq-num::before{ content:"(" attr(data-label) ")"; font:400 10pt var(--serif); color:var(--muted); }
61
- blockquote{ margin:var(--rhythm) 0; padding-left:1rem; border-left:2px solid var(--accent); font-style:italic; color:var(--ink-soft); }
62
- mark{ background:color-mix(in srgb, var(--accent) 14%, transparent); color:inherit; padding:0 .08em; }
63
- hr{ border:0; border-top:1px solid var(--rule-soft); margin:calc(var(--rhythm)*1.1) 0; max-width:var(--measure); }
64
- code,pre{ font-family:var(--mono); font-size:8.8pt; }
65
- pre{ background:#F5F6F8; border:1px solid var(--rule-soft); padding:.7rem .9rem; break-inside:avoid; white-space:pre-wrap; line-height:1.45; }
66
- a.xref-fig::after,a.xref-tbl::after,a.xref-eq::after{ content:none; }
67
- a.xref-sec::after{ content:target-counter(attr(href), sec); }
68
- section[data-type="references"]{ margin-top:calc(var(--rhythm)*1.5); }
69
- section[data-type="references"] > h2{ string-set:sectitle "References"; }
70
- section[data-type="references"] ol{ list-style:none; padding:0; margin:0; max-width:var(--measure); }
71
- section[data-type="references"] li{ counter-increment:ref; font-size:9pt; line-height:1.4; padding-left:2.2rem; text-indent:-2.2rem; margin:.3rem 0; break-inside:avoid; }
72
- section[data-type="references"] li::before{ content:"[" counter(ref) "]"; font-family:var(--sans); font-weight:600; display:inline-block; width:2.2rem; text-indent:0; }
73
- section[data-type="endnotes"]{ break-before:page; margin-top:calc(var(--rhythm)*1.5); }
74
- section[data-type="endnotes"] > h2{ string-set:sectitle "Notes"; }
75
- section[data-type="endnotes"] ol{ padding-left:1.4rem; max-width:var(--measure); }
76
- section[data-type="endnotes"] li{ font-size:9pt; line-height:1.45; margin:.35rem 0; break-inside:avoid; }
1
+ html {
2
+ font-size: 12pt;
3
+ }
4
+ body {
5
+ color: var(--ink);
6
+ background: var(--paper);
7
+ font: var(--body) / var(--lead) var(--serif);
8
+ font-variant-numeric: oldstyle-nums proportional-nums;
9
+ -webkit-font-smoothing: antialiased;
10
+ hyphens: var(--hyphenate);
11
+ counter-reset: sec fig tbl ref eq;
12
+ }
13
+ .doc-title {
14
+ font: 700 var(--t-title) / 1.1 var(--display);
15
+ margin: 0 0 var(--rhythm);
16
+ max-width: 30rem;
17
+ string-set: doctitle content(text);
18
+ }
19
+ .authors {
20
+ font: 500 11.5pt/1.4 var(--sans);
21
+ margin: 0 0 0.4rem;
22
+ }
23
+ .affil {
24
+ font: 400 9pt/1.4 var(--sans);
25
+ color: var(--muted);
26
+ margin: 0 0 calc(var(--rhythm) * 1.2);
27
+ }
28
+ .affil sup,
29
+ .authors sup {
30
+ font-size: 0.7em;
31
+ }
32
+ section[data-type='abstract'] {
33
+ border-top: 2px solid var(--accent);
34
+ border-bottom: 1px solid var(--rule);
35
+ padding: calc(var(--rhythm) * 0.75) 0;
36
+ margin: 0 0 calc(var(--rhythm) * 1.3);
37
+ max-width: var(--measure);
38
+ }
39
+ section[data-type='abstract'] > h2 {
40
+ all: unset;
41
+ display: block;
42
+ font: 600 8pt/1 var(--sans);
43
+ letter-spacing: 0.12em;
44
+ text-transform: uppercase;
45
+ color: var(--accent);
46
+ margin: 0 0 0.5rem;
47
+ counter-increment: none;
48
+ }
49
+ section[data-type='abstract'] > h2::before {
50
+ content: none;
51
+ }
52
+ section[data-type='abstract'] p {
53
+ margin: 0;
54
+ font-size: 9.8pt;
55
+ text-indent: 0;
56
+ }
57
+ .keywords {
58
+ font: 400 8.6pt/1.4 var(--sans);
59
+ color: var(--muted);
60
+ margin: 0.6rem 0 var(--rhythm);
61
+ }
62
+ .keywords b {
63
+ color: var(--ink-soft);
64
+ font-weight: 600;
65
+ }
66
+ section,
67
+ p,
68
+ ul,
69
+ ol,
70
+ blockquote {
71
+ max-width: var(--measure);
72
+ }
73
+ h2,
74
+ h3,
75
+ h4 {
76
+ font-family: var(--display);
77
+ color: var(--ink);
78
+ break-after: avoid-page;
79
+ }
80
+ h2 {
81
+ font-size: var(--t-h2);
82
+ font-weight: 700;
83
+ line-height: 1.15;
84
+ margin: calc(var(--rhythm) * 1.5) 0 calc(var(--rhythm) * 0.4);
85
+ string-set: sectitle content(text);
86
+ }
87
+ section:not([data-type='abstract']):not([data-type='frontmatter']):not(
88
+ [data-type='backmatter']
89
+ ):not([data-type='toc']):not([data-type='references']):not(
90
+ [data-type='endnotes']
91
+ ):not([data-type='acknowledgments']):not([data-type='part']) {
92
+ counter-increment: sec;
93
+ counter-reset: sub;
94
+ }
95
+ h2::before {
96
+ content: counter(sec) '\00a0\00a0';
97
+ color: var(--accent);
98
+ }
99
+ section[data-type='abstract'] > h2::before,
100
+ section[data-type='frontmatter'] > h2::before,
101
+ section[data-type='backmatter'] > h2::before,
102
+ section[data-type='toc'] > h2::before,
103
+ section[data-type='references'] > h2::before,
104
+ section[data-type='endnotes'] > h2::before,
105
+ section[data-type='acknowledgments'] > h2::before,
106
+ section[data-type='part'] > h2::before {
107
+ content: none;
108
+ }
109
+ h3 {
110
+ counter-increment: sub;
111
+ font-size: var(--t-h3);
112
+ font-weight: 600;
113
+ margin: calc(var(--rhythm) * 1) 0 calc(var(--rhythm) * 0.25);
114
+ }
115
+ h3::before {
116
+ content: counter(sec) '.' counter(sub) '\00a0\00a0';
117
+ color: var(--accent);
118
+ font-weight: 500;
119
+ }
120
+ h4 {
121
+ font-size: calc(var(--t-h3) * 0.88);
122
+ font-weight: 600;
123
+ margin: calc(var(--rhythm) * 0.8) 0 calc(var(--rhythm) * 0.2);
124
+ color: var(--ink-soft);
125
+ }
126
+ p {
127
+ margin: 0;
128
+ text-align: var(--text-align);
129
+ orphans: 3;
130
+ widows: 3;
131
+ }
132
+ p + p {
133
+ text-indent: 1.25em;
134
+ }
135
+ h2 + p,
136
+ h3 + p,
137
+ section[data-type='abstract'] + p,
138
+ figure + p {
139
+ text-indent: 0;
140
+ }
141
+ a {
142
+ color: var(--accent-ink);
143
+ text-decoration: none;
144
+ }
145
+ cite.ps-citation {
146
+ font-style: normal;
147
+ white-space: nowrap;
148
+ color: var(--accent-ink);
149
+ }
150
+ ul,
151
+ ol {
152
+ margin: var(--rhythm) 0;
153
+ padding-left: 1.4rem;
154
+ }
155
+ li {
156
+ margin: 0.15rem 0;
157
+ }
158
+ figure {
159
+ counter-increment: fig;
160
+ break-inside: avoid;
161
+ margin: calc(var(--rhythm) * 1.2) 0;
162
+ }
163
+ figcaption {
164
+ font: 400 8.8pt/1.4 var(--serif);
165
+ color: var(--ink-soft);
166
+ margin-top: 0.55rem;
167
+ max-width: var(--measure);
168
+ }
169
+ figcaption::before {
170
+ content: 'Figure ' attr(data-label) '.\00a0';
171
+ font-family: var(--sans);
172
+ font-weight: var(--caption-label-weight);
173
+ text-transform: var(--caption-label-transform);
174
+ color: var(--ink);
175
+ }
176
+ .table-wrap {
177
+ counter-increment: tbl;
178
+ break-inside: avoid;
179
+ margin: calc(var(--rhythm) * 1.2) 0;
180
+ }
181
+ .table-wrap > .tcaption {
182
+ font: 400 8.8pt/1.4 var(--serif);
183
+ color: var(--ink-soft);
184
+ margin: 0 0 0.45rem;
185
+ }
186
+ .table-wrap > .tcaption::before {
187
+ content: 'Table ' attr(data-label) '.\00a0';
188
+ font-family: var(--sans);
189
+ font-weight: var(--caption-label-weight);
190
+ text-transform: var(--caption-label-transform);
191
+ color: var(--ink);
192
+ }
193
+ table {
194
+ width: 100%;
195
+ font: 400 9pt/1.35 var(--serif);
196
+ }
197
+ thead th {
198
+ font-family: var(--sans);
199
+ font-weight: 600;
200
+ font-size: 8.4pt;
201
+ text-transform: var(--table-header-transform);
202
+ letter-spacing: var(--table-header-letter-spacing);
203
+ text-align: left;
204
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
205
+ color: var(--table-header-ink);
206
+ background: var(--table-header-bg);
207
+ border-bottom: var(--table-rule-width) solid var(--table-header-rule-color);
208
+ }
209
+ tbody td {
210
+ padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
211
+ border-bottom: var(--table-row-rule-width) solid var(--table-row-rule-color);
212
+ }
213
+ tbody tr:last-child td {
214
+ border-bottom: var(--table-rule-width) solid var(--rule);
215
+ }
216
+ .num {
217
+ text-align: right;
218
+ font-variant-numeric: tabular-nums;
219
+ }
220
+ .equation {
221
+ counter-increment: eq;
222
+ display: flex;
223
+ align-items: center;
224
+ gap: 1rem;
225
+ justify-content: center;
226
+ margin: calc(var(--rhythm) * 1) 0;
227
+ break-inside: avoid;
228
+ }
229
+ .equation .eq-body {
230
+ font: italic 400 12pt/1 var(--serif);
231
+ }
232
+ .equation .eq-num {
233
+ margin-left: auto;
234
+ }
235
+ .equation .eq-num::before {
236
+ content: '(' attr(data-label) ')';
237
+ font: 400 10pt var(--serif);
238
+ color: var(--muted);
239
+ }
240
+ blockquote {
241
+ margin: var(--rhythm) 0;
242
+ padding-left: 1rem;
243
+ border-left: 2px solid var(--accent);
244
+ font-style: italic;
245
+ color: var(--ink-soft);
246
+ }
247
+ mark {
248
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
249
+ color: inherit;
250
+ padding: 0 0.08em;
251
+ }
252
+ hr {
253
+ border: 0;
254
+ border-top: 1px solid var(--rule-soft);
255
+ margin: calc(var(--rhythm) * 1.1) 0;
256
+ max-width: var(--measure);
257
+ }
258
+ code,
259
+ pre {
260
+ font-family: var(--mono);
261
+ font-size: 8.8pt;
262
+ }
263
+ pre {
264
+ background: #f5f6f8;
265
+ border: 1px solid var(--rule-soft);
266
+ padding: 0.7rem 0.9rem;
267
+ break-inside: avoid;
268
+ white-space: pre-wrap;
269
+ line-height: 1.45;
270
+ }
271
+ a.xref-fig::after,
272
+ a.xref-tbl::after,
273
+ a.xref-eq::after {
274
+ content: none;
275
+ }
276
+ a.xref-sec::after {
277
+ content: target-counter(attr(href), sec);
278
+ }
279
+ section[data-type='references'] {
280
+ margin-top: calc(var(--rhythm) * 1.5);
281
+ }
282
+ section[data-type='references'] > h2 {
283
+ string-set: sectitle 'References';
284
+ }
285
+ section[data-type='references'] ol {
286
+ list-style: none;
287
+ padding: 0;
288
+ margin: 0;
289
+ max-width: var(--measure);
290
+ }
291
+ section[data-type='references'] li {
292
+ counter-increment: ref;
293
+ font-size: 9pt;
294
+ line-height: 1.4;
295
+ padding-left: 2.2rem;
296
+ text-indent: -2.2rem;
297
+ margin: 0.3rem 0;
298
+ break-inside: avoid;
299
+ }
300
+ section[data-type='references'] li::before {
301
+ content: '[' counter(ref) ']';
302
+ font-family: var(--sans);
303
+ font-weight: 600;
304
+ display: inline-block;
305
+ width: 2.2rem;
306
+ text-indent: 0;
307
+ }
308
+ section[data-type='endnotes'] {
309
+ break-before: page;
310
+ margin-top: calc(var(--rhythm) * 1.5);
311
+ }
312
+ section[data-type='endnotes'] > h2 {
313
+ string-set: sectitle 'Notes';
314
+ }
315
+ section[data-type='endnotes'] ol {
316
+ padding-left: 1.4rem;
317
+ max-width: var(--measure);
318
+ }
319
+ section[data-type='endnotes'] li {
320
+ font-size: 9pt;
321
+ line-height: 1.45;
322
+ margin: 0.35rem 0;
323
+ break-inside: avoid;
324
+ }
@@ -29,7 +29,7 @@ const LIBRARY: {
29
29
  'serif:bracketed': '"Source Serif 4", Georgia, serif',
30
30
  'serif:hairline': '"Newsreader", Georgia, serif',
31
31
  'serif:wedge': '"Spectral", Georgia, serif',
32
- sans: '"Source Sans 3", system-ui, sans-serif',
32
+ sans: '"Archivo", system-ui, sans-serif',
33
33
  },
34
34
  caption: {
35
35
  sans: '"Archivo", system-ui, sans-serif',
@@ -187,8 +187,8 @@ describe('buildPureRenderHtmlDocument', () => {
187
187
  ).toContain('--table-row-rule-color:transparent;')
188
188
  expect(
189
189
  new Set(
190
- assembled.map(item =>
191
- item.html.match(/--table-header-bg:([^;]+);/)?.[1] ?? '',
190
+ assembled.map(
191
+ item => item.html.match(/--table-header-bg:([^;]+);/)?.[1] ?? '',
192
192
  ),
193
193
  ).size,
194
194
  ).toBeGreaterThan(1)
@@ -174,7 +174,12 @@ describe('print style extraction contract', () => {
174
174
  },
175
175
  ],
176
176
  type: [
177
- { role: 'body', class: 'serif', serif_detail: 'bracketed', confidence: 0.86 },
177
+ {
178
+ role: 'body',
179
+ class: 'serif',
180
+ serif_detail: 'bracketed',
181
+ confidence: 0.86,
182
+ },
178
183
  ],
179
184
  text_setting: { alignment: 'justified', confidence: 0.82 },
180
185
  page_model: { columns: 1, confidence: 0.8 },
@@ -199,9 +204,7 @@ describe('print style extraction contract', () => {
199
204
  confidence: 0.8,
200
205
  },
201
206
  ],
202
- type: [
203
- { role: 'body', class: 'sans', confidence: 0.72 },
204
- ],
207
+ type: [{ role: 'body', class: 'sans', confidence: 0.72 }],
205
208
  text_setting: { alignment: 'flush-left', confidence: 0.78 },
206
209
  page_model: { columns: 2, confidence: 0.74 },
207
210
  opener: { ornament: 'rule', confidence: 0.72 },
@@ -212,13 +215,20 @@ describe('print style extraction contract', () => {
212
215
  ])
213
216
 
214
217
  const result = compilePrintTheme(profile)
215
- const decisionText = result.decisions.map(([, message]) => message).join('\n')
218
+ const decisionText = result.decisions
219
+ .map(([, message]) => message)
220
+ .join('\n')
216
221
 
217
222
  expect(decisionText).toContain('Reference conflict: accent color disagrees')
218
- expect(decisionText).toContain('Reference conflict: body font class disagrees')
223
+ expect(decisionText).toContain(
224
+ 'Reference conflict: body font class disagrees',
225
+ )
219
226
  expect(decisionText).toContain('Reference conflict: page columns disagrees')
220
227
  expect(result.theme?.enforced_rules).toEqual(
221
- expect.arrayContaining(['keep rules sparse', 'keep ornaments restrained']),
228
+ expect.arrayContaining([
229
+ 'keep rules sparse',
230
+ 'keep ornaments restrained',
231
+ ]),
222
232
  )
223
233
  expect(result.theme?.enforced_rules?.join('\n')).not.toContain(
224
234
  'Reference conflict:',
@@ -302,12 +312,14 @@ describe('print style extraction contract', () => {
302
312
  const close = vi.fn()
303
313
  const bitmap = { close }
304
314
  const pixels = new Uint8ClampedArray([
305
- 250, 250, 250, 255, 250, 250, 250, 255, 250, 250, 250, 255, 250, 250,
306
- 250, 255, 24, 24, 24, 255, 24, 24, 24, 255, 24, 24, 24, 255, 24, 24, 24,
307
- 255, 96, 120, 72, 255, 96, 120, 72, 255, 96, 120, 72, 255, 96, 120,
308
- 72, 255,
315
+ 250, 250, 250, 255, 250, 250, 250, 255, 250, 250, 250, 255, 250, 250, 250,
316
+ 255, 24, 24, 24, 255, 24, 24, 24, 255, 24, 24, 24, 255, 24, 24, 24, 255,
317
+ 96, 120, 72, 255, 96, 120, 72, 255, 96, 120, 72, 255, 96, 120, 72, 255,
309
318
  ])
310
- vi.stubGlobal('createImageBitmap', vi.fn(async () => bitmap))
319
+ vi.stubGlobal(
320
+ 'createImageBitmap',
321
+ vi.fn(async () => bitmap),
322
+ )
311
323
  const originalCreateElement = document.createElement.bind(document)
312
324
  const drawImage = vi.fn()
313
325
  vi.spyOn(document, 'createElement').mockImplementation(tagName => {
@@ -712,8 +712,7 @@ export function buildWriterPrintStyleProfileFromReference({
712
712
  const sans = text.includes('sans') || text.includes('modern')
713
713
  const airy = text.includes('airy') || text.includes('open')
714
714
  const compact = text.includes('compact') || text.includes('dense')
715
- const highContrast =
716
- text.includes('high contrast') || text.includes('crisp')
715
+ const highContrast = text.includes('high contrast') || text.includes('crisp')
717
716
  const flush = !text.includes('justify')
718
717
  return {
719
718
  schema_version: '1.0',
@@ -889,7 +888,8 @@ function detectReconciliationConflicts(
889
888
  const conflicts: PrintStyleRule[] = []
890
889
  const addConflict = (label: string, values: readonly FieldValue[]): void => {
891
890
  const confident = values.filter(
892
- item => item.value !== undefined && item.value !== '' && item.confidence >= 0.6,
891
+ item =>
892
+ item.value !== undefined && item.value !== '' && item.confidence >= 0.6,
893
893
  )
894
894
  const unique = Array.from(
895
895
  new Map(confident.map(item => [String(item.value), item])).values(),
@@ -898,7 +898,9 @@ function detectReconciliationConflicts(
898
898
  conflicts.push({
899
899
  rule: `Reference conflict: ${label} disagrees across uploaded images (${unique
900
900
  .map(item => `${item.source}: ${item.value}`)
901
- .join('; ')}). Highest-confidence value was used; review before saving as a shared theme.`,
901
+ .join(
902
+ '; ',
903
+ )}). Highest-confidence value was used; review before saving as a shared theme.`,
902
904
  evidence: unique.map(item => item.source).join(', '),
903
905
  confidence: Math.min(0.9, average(unique.map(item => item.confidence))),
904
906
  })
@@ -911,10 +913,11 @@ function detectReconciliationConflicts(
911
913
  'body font class',
912
914
  profiles.map((profile, index) => ({
913
915
  source: sourceId(profile, index),
914
- value: profile.observations.type?.find(item => item.role === 'body')?.class,
916
+ value: profile.observations.type?.find(item => item.role === 'body')
917
+ ?.class,
915
918
  confidence:
916
- profile.observations.type?.find(item => item.role === 'body')?.confidence ??
917
- 0,
919
+ profile.observations.type?.find(item => item.role === 'body')
920
+ ?.confidence ?? 0,
918
921
  })),
919
922
  )
920
923
  addConflict(
@@ -1,3 +1,17 @@
1
- .doc-title,.authors,.affil,section[data-type="abstract"]{ break-after:avoid; }
2
- .fn{ float:footnote; font-size:8.4pt; line-height:1.3; }
3
- @page{ @footnote{ border-top:.5px solid var(--rule); padding-top:2pt; } }
1
+ .doc-title,
2
+ .authors,
3
+ .affil,
4
+ section[data-type='abstract'] {
5
+ break-after: avoid;
6
+ }
7
+ .fn {
8
+ float: footnote;
9
+ font-size: 8.4pt;
10
+ line-height: 1.3;
11
+ }
12
+ @page {
13
+ @footnote {
14
+ border-top: 0.5px solid var(--rule);
15
+ padding-top: 2pt;
16
+ }
17
+ }
@@ -351,32 +351,30 @@ function normalizeCitationLinks(doc: Document): void {
351
351
  )
352
352
  .forEach(element => referenceIds.add(element.id))
353
353
 
354
- doc.body
355
- .querySelectorAll<HTMLElement>('cite[data-ref-ids]')
356
- .forEach(cite => {
357
- const refIds = (cite.getAttribute('data-ref-ids') ?? '')
358
- .split(',')
359
- .map(id => id.trim())
360
- .filter(Boolean)
361
- if (refIds.length === 0) return
362
-
363
- const targets = refIds.map(refId => citationTargetFor(refId, referenceIds))
364
- if (targets.some(target => !target)) return
365
-
366
- cite.classList.add('ps-citation')
367
- const labels = citationLabels(cite.textContent ?? '', refIds.length)
368
- cite.replaceChildren()
369
- if (targets.length === 1) {
370
- cite.append(citationAnchor(doc, targets[0] as string, labels[0]))
371
- return
372
- }
373
- cite.append(doc.createTextNode('['))
374
- targets.forEach((target, index) => {
375
- if (index > 0) cite.append(doc.createTextNode(', '))
376
- cite.append(citationAnchor(doc, target as string, labels[index]))
377
- })
378
- cite.append(doc.createTextNode(']'))
354
+ doc.body.querySelectorAll<HTMLElement>('cite[data-ref-ids]').forEach(cite => {
355
+ const refIds = (cite.getAttribute('data-ref-ids') ?? '')
356
+ .split(',')
357
+ .map(id => id.trim())
358
+ .filter(Boolean)
359
+ if (refIds.length === 0) return
360
+
361
+ const targets = refIds.map(refId => citationTargetFor(refId, referenceIds))
362
+ if (targets.some(target => !target)) return
363
+
364
+ cite.classList.add('ps-citation')
365
+ const labels = citationLabels(cite.textContent ?? '', refIds.length)
366
+ cite.replaceChildren()
367
+ if (targets.length === 1) {
368
+ cite.append(citationAnchor(doc, targets[0] as string, labels[0]))
369
+ return
370
+ }
371
+ cite.append(doc.createTextNode('['))
372
+ targets.forEach((target, index) => {
373
+ if (index > 0) cite.append(doc.createTextNode(', '))
374
+ cite.append(citationAnchor(doc, target as string, labels[index]))
379
375
  })
376
+ cite.append(doc.createTextNode(']'))
377
+ })
380
378
  }
381
379
 
382
380
  function citationTargetFor(
@@ -396,7 +394,11 @@ function citationLabels(text: string, count: number): string[] {
396
394
  return Array.from({ length: count }, (_, index) => String(index + 1))
397
395
  }
398
396
 
399
- function citationAnchor(doc: Document, targetId: string, label: string): Element {
397
+ function citationAnchor(
398
+ doc: Document,
399
+ targetId: string,
400
+ label: string,
401
+ ): Element {
400
402
  const anchor = doc.createElement('a')
401
403
  anchor.setAttribute('href', `#${targetId}`)
402
404
  anchor.textContent = label