arcane-os 0.46.0 → 0.48.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.
@@ -0,0 +1,235 @@
1
+ /* Shared paper presentation for direct pages and rendered PrintView snapshots.
2
+ * Theme/document styles import this file. PrintView loads the same complete
3
+ * text before registration so native beforeprint performs no asynchronous I/O.
4
+ */
5
+ :root,
6
+ :host{
7
+ --arcane-print-paper:rgb(255, 255, 255);
8
+ --arcane-print-text:rgb(23, 34, 56);
9
+ --arcane-print-secondary:rgb(229, 233, 243);
10
+ --arcane-print-border:rgb(203, 211, 226);
11
+ --arcane-print-focus:rgb(118, 87, 213);
12
+ --arcane-print-muted:rgb(95, 107, 130);
13
+ --arcane-print-success:rgb(39, 122, 75);
14
+ --arcane-print-warning:rgb(154, 101, 0);
15
+ --arcane-print-danger:rgb(165, 56, 56);
16
+ --arcane-print-review:rgb(133, 85, 165);
17
+ --arcane-print-shadow:rgba(23, 34, 56, .16);
18
+ --arcane-print-platinum:rgb(102, 112, 133);
19
+ --arcane-print-icon-filter:none;
20
+ --arcane-print-file-icon-filter:hue-rotate(8deg) saturate(.62) brightness(.86);
21
+ }
22
+
23
+ /* Snapshot rules are scoped to PrintView-owned nodes, including its shadow
24
+ * host. The source document's typography and artwork remain on the clones.
25
+ */
26
+ :host([data-arcane-print-stage]){
27
+ color-scheme:light!important;
28
+ color:var(--arcane-print-text)!important;
29
+ background:var(--arcane-print-paper)!important;
30
+ font:12pt/1.5 serif;
31
+ }
32
+
33
+ :host([data-arcane-print-stage])>h1{
34
+ margin:0 0 .75em;
35
+ font-size:1.5em;
36
+ line-height:1.2;
37
+ }
38
+
39
+ [data-arcane-print-node]:not(svg,svg *,img,video,audio),
40
+ [data-arcane-print-node]:not(svg,svg *,img,video,audio)::before,
41
+ [data-arcane-print-node]:not(svg,svg *,img,video,audio)::after{
42
+ color:var(--arcane-print-text)!important;
43
+ background-color:transparent!important;
44
+ border-color:var(--arcane-print-border)!important;
45
+ color-scheme:light!important;
46
+ -webkit-text-fill-color:currentColor!important;
47
+ -webkit-text-stroke:0!important;
48
+ text-decoration-color:currentColor!important;
49
+ text-shadow:none!important;
50
+ box-shadow:none!important;
51
+ }
52
+
53
+ a[data-arcane-print-node]:not(svg *){text-decoration:underline!important;}
54
+ table[data-arcane-print-node]:not(svg *){border-collapse:collapse!important;}
55
+ th[data-arcane-print-node]:not(svg *),
56
+ td[data-arcane-print-node]:not(svg *){
57
+ border:1px solid var(--arcane-print-border)!important;
58
+ padding:.35em .5em!important;
59
+ }
60
+
61
+ [data-arcane-print-expand]{
62
+ height:auto!important;
63
+ min-height:0!important;
64
+ max-height:none!important;
65
+ width:auto!important;
66
+ min-width:0!important;
67
+ max-width:100%!important;
68
+ overflow:visible!important;
69
+ contain:none!important;
70
+ content-visibility:visible!important;
71
+ grid-template-rows:none!important;
72
+ break-inside:auto!important;
73
+ }
74
+
75
+ img[data-arcane-print-node]{max-width:100%!important;height:auto!important;}
76
+ [data-arcane-print-static]{position:static!important;}
77
+ [data-arcane-print-root]{visibility:visible!important;}
78
+ [data-arcane-print-block]{display:block!important;}
79
+ pre[data-arcane-print-node]{white-space:pre-wrap!important;overflow-wrap:anywhere!important;}
80
+ table[data-arcane-print-node]{table-layout:auto!important;}
81
+ thead[data-arcane-print-node]{display:table-header-group!important;}
82
+ tfoot[data-arcane-print-node]{display:table-footer-group!important;}
83
+ td[data-arcane-print-node],
84
+ th[data-arcane-print-node]{overflow-wrap:anywhere!important;white-space:normal!important;}
85
+
86
+ /* Chat supplies the rendered transcript, not controls or session status.
87
+ * Keep public tool messages; inspection details and thinking are transient.
88
+ */
89
+ .chat_output[data-arcane-print-node]{
90
+ display:block!important;
91
+ margin:0!important;
92
+ padding:0!important;
93
+ border:0!important;
94
+ border-radius:0!important;
95
+ }
96
+
97
+ .chat_output[data-arcane-print-node]>li{
98
+ display:block!important;
99
+ float:none!important;
100
+ clear:both!important;
101
+ max-inline-size:100%!important;
102
+ text-align:start!important;
103
+ margin:0 0 1em!important;
104
+ padding:0!important;
105
+ border:0!important;
106
+ border-radius:0!important;
107
+ }
108
+
109
+ .chat_output[data-arcane-print-node]>li [data-arcane-print-node]:not(.message_timestamp){
110
+ text-align:start!important;
111
+ }
112
+
113
+ .chat_output[data-arcane-print-node]>li>.thinking,
114
+ .chat_output[data-arcane-print-node]>li>.message_tool_details,
115
+ .chat_output[data-arcane-print-node]>li>.message_tool_calls>.message_tool_call>.message_tool_details,
116
+ .chat_output[data-arcane-print-node]>li:has(>.thinking):has(>.markdown:empty):not(:has(.message_tool_message)){
117
+ display:none!important;
118
+ }
119
+
120
+ [data-arcane-print-stage]{display:none!important;}
121
+
122
+ @media print{
123
+ @page{margin:1in;}
124
+
125
+ :root,
126
+ body,
127
+ [data-arcane-palette]{
128
+ color-scheme:light!important;
129
+ --background:var(--arcane-print-paper)!important;
130
+ --modal-background:var(--arcane-print-paper)!important;
131
+ --text-color:var(--arcane-print-text)!important;
132
+ --primary-color:var(--arcane-print-text)!important;
133
+ --secondary-color:var(--arcane-print-secondary)!important;
134
+ --accent-color:var(--focus-color)!important;
135
+ --button-text-color:var(--arcane-print-paper)!important;
136
+ --border-color:var(--arcane-print-border)!important;
137
+ --focus-color:var(--arcane-print-focus)!important;
138
+ --muted-text-color:var(--arcane-print-muted)!important;
139
+ --success-color:var(--arcane-print-success)!important;
140
+ --warning-color:var(--arcane-print-warning)!important;
141
+ --danger-color:var(--arcane-print-danger)!important;
142
+ --review-color:var(--arcane-print-review)!important;
143
+ --shadow-color:var(--arcane-print-shadow)!important;
144
+ --platinum:var(--arcane-print-platinum)!important;
145
+ --icon-filter:var(--arcane-print-icon-filter)!important;
146
+ --file-icon-filter:var(--arcane-print-file-icon-filter)!important;
147
+ }
148
+
149
+ html,
150
+ body{
151
+ margin:0;
152
+ background-color:var(--modal-background);
153
+ color:var(--text-color);
154
+ }
155
+
156
+ /* The shared screen shell has a sidebar grid and a viewport-height main
157
+ * scroller. Paper uses the same main content in ordinary document flow.
158
+ */
159
+ html:has(>body>main),
160
+ body:has(>main),
161
+ body>main,
162
+ body>main .data-workspace{
163
+ display:block!important;
164
+ position:static!important;
165
+ width:auto!important;
166
+ height:auto!important;
167
+ min-height:0!important;
168
+ max-height:none!important;
169
+ overflow:visible!important;
170
+ contain:none!important;
171
+ grid-template-columns:none!important;
172
+ grid-template-rows:none!important;
173
+ margin:0!important;
174
+ padding:0!important;
175
+ border:0!important;
176
+ border-radius:0!important;
177
+ box-shadow:none!important;
178
+ }
179
+
180
+ body:has(>main)>.header,
181
+ body:has(>main)>.nav{
182
+ display:none!important;
183
+ }
184
+
185
+ /* Expand only when an owned rendered snapshot is actually present. */
186
+ html:root:has(>body>[data-arcane-print-stage]),
187
+ html:root>body:has(>[data-arcane-print-stage]){
188
+ display:block!important;
189
+ height:auto!important;
190
+ min-height:0!important;
191
+ max-height:none!important;
192
+ overflow:visible!important;
193
+ contain:none!important;
194
+ margin:0!important;
195
+ padding:0!important;
196
+ border:0!important;
197
+ background:var(--arcane-print-paper)!important;
198
+ color:var(--arcane-print-text)!important;
199
+ color-scheme:light!important;
200
+ }
201
+
202
+ html:root>body:has(>[data-arcane-print-stage])>*:not([data-arcane-print-stage]),
203
+ html:root>body:has(>[data-arcane-print-stage])::before,
204
+ html:root>body:has(>[data-arcane-print-stage])::after{
205
+ display:none!important;
206
+ }
207
+
208
+ html:root>body>[data-arcane-print-stage]{
209
+ display:block!important;
210
+ position:static!important;
211
+ width:auto!important;
212
+ height:auto!important;
213
+ overflow:visible!important;
214
+ margin:0!important;
215
+ padding:0!important;
216
+ border:0!important;
217
+ }
218
+
219
+ body.static-doc-site :is(.static-site-header,.static-site-footer,.static-section-nav,.static-previous-next,.static-related,.static-document__source,.skip-link){
220
+ display:none!important;
221
+ }
222
+
223
+ body.static-doc-site :is(.static-site-main,.static-site-main--document){
224
+ max-inline-size:none!important;
225
+ padding:0!important;
226
+ }
227
+
228
+ body.static-doc-site .static-document-layout{display:block!important;}
229
+ body.static-doc-site .static-document{inline-size:100%!important;}
230
+ body.static-doc-site .static-document__content table{display:table!important;overflow:visible!important;}
231
+ body.static-doc-site .static-document__content table :where(code,kbd){
232
+ overflow-wrap:anywhere!important;
233
+ word-break:break-word!important;
234
+ }
235
+ }
@@ -1,3 +1,5 @@
1
+ @import url('./print.css');
2
+
1
3
  /* Shared default and named palettes. layout.css imports this owner, and
2
4
  * standalone applications may load it directly before their own styles.
3
5
  * data-user-skin selects the root palette; data-arcane-palette scopes a swatch.
@@ -328,43 +330,3 @@ body{
328
330
  transition-duration:.01ms !important;
329
331
  }
330
332
 
331
- /* Paper uses the existing base light palette regardless of the screen skin.
332
- * Print-only importance also overrides custom-theme inline tokens; no saved
333
- * preference, screen layout, media paint, or scrolling state changes here.
334
- */
335
- @media print {
336
- @page {
337
- margin: 15mm;
338
- }
339
-
340
- :root,
341
- body,
342
- [data-arcane-palette] {
343
- color-scheme: light !important;
344
- --background: rgb(255, 255, 255) !important;
345
- --modal-background: rgb(255, 255, 255) !important;
346
- --text-color: rgb(23, 34, 56) !important;
347
- --primary-color: rgb(23, 34, 56) !important;
348
- --secondary-color: rgb(229, 233, 243) !important;
349
- --accent-color: var(--focus-color) !important;
350
- --button-text-color: rgb(255, 255, 255) !important;
351
- --border-color: rgb(203, 211, 226) !important;
352
- --focus-color: rgb(118, 87, 213) !important;
353
- --muted-text-color: rgb(95, 107, 130) !important;
354
- --success-color: rgb(39, 122, 75) !important;
355
- --warning-color: rgb(154, 101, 0) !important;
356
- --danger-color: rgb(165, 56, 56) !important;
357
- --review-color: rgb(133, 85, 165) !important;
358
- --shadow-color: rgba(23, 34, 56, .16) !important;
359
- --platinum: rgb(102, 112, 133) !important;
360
- --icon-filter: none !important;
361
- --file-icon-filter: hue-rotate(8deg) saturate(.62) brightness(.86) !important;
362
- }
363
-
364
- html,
365
- body {
366
- margin: 0;
367
- background-color: var(--modal-background);
368
- color: var(--text-color);
369
- }
370
- }
@@ -2081,8 +2081,10 @@ class AI {
2081
2081
  #assertDeviceSpeechConfiguration(configuration){
2082
2082
  for(const routeName of ['default','localOnly']){
2083
2083
  const selection=configuration?.stt?.[routeName];
2084
- if(selection&&selection.localOnly!==true){
2085
- const error=new TypeError('Speech recognition supports on-device providers only.');
2084
+ const liveCapture=selection
2085
+ &&this.#providerRuntime.supportsTranscriptionCapture(selection.providerId);
2086
+ if(selection&&selection.localOnly!==true&&!liveCapture){
2087
+ const error=new TypeError('Speech recognition requires an on-device or explicitly selected live-capture provider.');
2086
2088
  error.code='AI_STT_DEVICE_ONLY';
2087
2089
  throw error;
2088
2090
  }
@@ -3430,8 +3432,9 @@ class AI {
3430
3432
  if(provider!==null&&provider?.role!==role){
3431
3433
  throw new TypeError('The speech provider must implement the selected role.');
3432
3434
  }
3433
- if(role==='stt'&&provider&&provider.localOnly!==true){
3434
- const error=new TypeError('Speech recognition supports on-device providers only.');
3435
+ if(role==='stt'&&provider&&provider.localOnly!==true
3436
+ &&!is.function(provider.createCapture)){
3437
+ const error=new TypeError('Speech recognition requires an on-device or explicitly selected live-capture provider.');
3435
3438
  error.code='AI_STT_DEVICE_ONLY';
3436
3439
  throw error;
3437
3440
  }
@@ -6875,6 +6878,14 @@ class AI {
6875
6878
  }
6876
6879
  }
6877
6880
 
6881
+ supportsTranscriptionCapture(){
6882
+ return this.#providerRuntime.supportsTranscriptionCapture();
6883
+ }
6884
+
6885
+ createTranscriptionCapture(options={}){
6886
+ return this.#providerRuntime.createTranscriptionCapture(options);
6887
+ }
6888
+
6878
6889
  async fetchSTT(audioFile,signal=null){
6879
6890
  const callId=this.#traceSpeech('fetchSTT.call',{audioFile,aborted:signal?.aborted});
6880
6891
  try{
@@ -1366,6 +1366,9 @@ function validateProvider(provider) {
1366
1366
  for (const method of PROVIDER_METHODS) {
1367
1367
  record[method] = provider[method].bind(provider);
1368
1368
  }
1369
+ if (provider.role === 'stt' && is.function(provider.createCapture)) {
1370
+ record.createCapture = provider.createCapture.bind(provider);
1371
+ }
1369
1372
  const admitted = completeValue(record);
1370
1373
  PROVIDER_RECORDS.set(provider, admitted);
1371
1374
  return admitted;
@@ -4103,6 +4106,121 @@ export class AIProviderRuntime {
4103
4106
  return this.#roleRequestAlias('llm', 'stream', payload, options);
4104
4107
  }
4105
4108
 
4109
+ supportsTranscriptionCapture(providerId = null) {
4110
+ const slot = this.#slots.stt;
4111
+ const provider = providerId === null
4112
+ ? this.#providerFor(slot)
4113
+ : this.#providers.get(providerKey('stt', providerId));
4114
+ return is.function(provider?.createCapture);
4115
+ }
4116
+
4117
+ createTranscriptionCapture(options = {}) {
4118
+ this.#assertOpen();
4119
+ this.#assertNotConfiguring();
4120
+ const slot = this.#slots.stt;
4121
+ const provider = this.#providerFor(slot);
4122
+ if (!is.function(provider?.createCapture)) return null;
4123
+
4124
+ const runtime = this;
4125
+ const generation = slot.generation;
4126
+ const capture = provider.createCapture(options);
4127
+ const controller = new AbortController();
4128
+ let requestRecord = null;
4129
+ let detachSignal = null;
4130
+ let started = false;
4131
+ let closed = false;
4132
+ const done = Promise.resolve(capture.done).finally(
4133
+ function releaseTranscriptionCapture() {
4134
+ closed = true;
4135
+ detachSignal?.();
4136
+ if (!requestRecord) return;
4137
+ slot.activeRequests.delete(requestRecord.requestSequence);
4138
+ runtime.#drainRoleRequestQueue(slot);
4139
+ if (slot.generation !== generation || slot.unloadPromise) return;
4140
+ if (slot.activeRequests.size || slot.requestQueue.length) {
4141
+ runtime.#publishRoleRequestState(slot);
4142
+ return;
4143
+ }
4144
+ const status = validateProviderStatus(provider.status());
4145
+ slot.ready = status.state === 'ready' && status.loaded && !status.busy;
4146
+ publishAIRuntimeRoleState(
4147
+ 'stt',
4148
+ roleRecord(
4149
+ 'stt',
4150
+ slot.selection,
4151
+ {state: slot.ready ? 'ready' : 'unloaded', loaded: status.loaded}
4152
+ )
4153
+ );
4154
+ }
4155
+ );
4156
+ done.catch(
4157
+ function observeTranscriptionCaptureCleanupFailure(error) {
4158
+ arcaneLogging.error('Transcription capture cleanup failed.', error);
4159
+ }
4160
+ );
4161
+ // Capture has its own synchronous start boundary so native microphone
4162
+ // permission retains the originating user gesture. It is never queued.
4163
+ return {
4164
+ done,
4165
+ start({signal} = {}) {
4166
+ if (started || closed) return Promise.resolve(false);
4167
+ try {
4168
+ runtime.#assertOpen();
4169
+ runtime.#assertNotConfiguring();
4170
+ const status = validateProviderStatus(provider.status());
4171
+ if (slot.generation !== generation || !slot.ready
4172
+ || slot.unloadPromise || slot.disposePromise
4173
+ || slot.activeRequests.size || slot.requestQueue.length
4174
+ || status.state !== 'ready' || !status.loaded || status.busy) {
4175
+ throw operationError(
4176
+ 'The selected transcription capture provider is not ready.',
4177
+ 'ARCANE_AI_ROLE_NOT_READY'
4178
+ );
4179
+ }
4180
+ assertAbortSignal(signal);
4181
+ started = true;
4182
+ detachSignal = runtime.#forwardAbort(signal, controller);
4183
+ const requestSequence = runtime.#nextRequestSequence(slot);
4184
+ requestRecord = {
4185
+ controller,
4186
+ requestSequence,
4187
+ operationId: runtime.#nextOperationId(slot, 'capture'),
4188
+ promise: done,
4189
+ cancel: function cancelOwnedTranscriptionCapture(reason) {
4190
+ controller.abort(reason);
4191
+ capture.cancel();
4192
+ return done;
4193
+ }
4194
+ };
4195
+ slot.activeRequests.set(requestSequence, requestRecord);
4196
+ runtime.#publishRoleRequestState(slot);
4197
+ const starting = capture.start({signal: controller.signal});
4198
+ return Promise.resolve(starting).catch(
4199
+ function releaseFailedTranscriptionCaptureStart(error) {
4200
+ capture.cancel();
4201
+ throw error;
4202
+ }
4203
+ );
4204
+ } catch (error) {
4205
+ capture.cancel();
4206
+ throw error;
4207
+ }
4208
+ },
4209
+ stop() {
4210
+ capture.stop();
4211
+ return done;
4212
+ },
4213
+ cancel() {
4214
+ controller.abort();
4215
+ capture.cancel();
4216
+ },
4217
+ destroy() {
4218
+ controller.abort();
4219
+ capture.destroy();
4220
+ }
4221
+ };
4222
+ }
4223
+
4106
4224
  transcribe(payload, options = {}) {
4107
4225
  arcaneLogging.debug('[Arcane speech runtime] transcribe', payload, options);
4108
4226
  return this.#roleRequestAlias('stt', 'transcribe', payload, options);
@@ -1,5 +1,13 @@
1
1
  import Is from 'strong-type';
2
- import {arcaneLightThemeTokens} from '../entities/Theme.js';
2
+
3
+ // Components import this module independently of their rendering. Await only
4
+ // the required print stylesheet here so every registered view is ready for the
5
+ // synchronous native beforeprint event, with no stylesheet fetch during print.
6
+ const printResponse=await fetch(new URL('../css/print.css',import.meta.url));
7
+ if(!printResponse.ok){
8
+ throw new Error(`Unable to load shared print styles: HTTP ${printResponse.status}.`);
9
+ }
10
+ const printStyles=await printResponse.text();
3
11
 
4
12
  const is=new Is(false);
5
13
  const registries=new WeakMap();
@@ -401,38 +409,13 @@ function capture(registry,session){
401
409
  const heading=document.createElement('h1');
402
410
  heading.textContent=session.title;
403
411
  const rendered=copyRendered(session.content,state,true);
404
- // Screen layout and fonts describe the rendered content; screen-theme paint
405
- // does not describe a readable paper surface. Keep this palette in the
406
- // snapshot, including its pseudo-elements, without recoloring SVG artwork.
407
- styles.textContent=`
408
- :host{color-scheme:light!important;color:${arcaneLightThemeTokens.text}!important;background:${arcaneLightThemeTokens.surface}!important;font:12pt/1.5 serif}
409
- :host>h1{margin:0 0 .75em;font-size:1.5em;line-height:1.2}
410
- [data-arcane-print-node]:not(svg,svg *,img,video,audio),
411
- [data-arcane-print-node]:not(svg,svg *,img,video,audio)::before,
412
- [data-arcane-print-node]:not(svg,svg *,img,video,audio)::after{
413
- color:${arcaneLightThemeTokens.text}!important;background-color:transparent!important;
414
- border-color:${arcaneLightThemeTokens.border}!important;color-scheme:light!important;
415
- -webkit-text-fill-color:currentColor!important;-webkit-text-stroke:0!important;
416
- text-decoration-color:currentColor!important;text-shadow:none!important;box-shadow:none!important
417
- }
418
- a[data-arcane-print-node]:not(svg *){text-decoration:underline!important}
419
- table[data-arcane-print-node]:not(svg *){border-collapse:collapse!important}
420
- th[data-arcane-print-node]:not(svg *),td[data-arcane-print-node]:not(svg *){border:1px solid ${arcaneLightThemeTokens.border}!important;padding:.35em .5em!important}
421
- ${state.rules.join('\n')}
422
- `;
412
+ // Only captured pseudo-element declarations are generated here. Authored
413
+ // print palette, page margins, and expansion rules share the CSS owner.
414
+ styles.textContent=printStyles+'\n'+state.rules.join('\n');
423
415
  root.append(styles,heading,rendered);
424
416
  const sheet=document.createElement('style');
425
417
  session.sheet=sheet;
426
- sheet.textContent=`
427
- [data-arcane-print-stage]{display:none!important}
428
- @media print{
429
- @page{margin:15mm}
430
- html:root,html:root>body{display:block!important;height:auto!important;min-height:0!important;max-height:none!important;overflow:visible!important;contain:none!important;margin:0!important;padding:0!important;border:0!important;background:${arcaneLightThemeTokens.surface}!important;color:${arcaneLightThemeTokens.text}!important;color-scheme:light!important}
431
- html:root>body>*:not([data-arcane-print-stage]){display:none!important}
432
- html:root>body::before,html:root>body::after{display:none!important}
433
- html:root>body>[data-arcane-print-stage]{display:block!important;position:static!important;width:auto!important;height:auto!important;overflow:visible!important;margin:0!important;padding:0!important;border:0!important}
434
- }
435
- `;
418
+ sheet.textContent=printStyles;
436
419
  document.head.append(sheet);
437
420
  document.body.append(stage);
438
421
  session.originalTitle=document.title;
@@ -523,36 +506,17 @@ function copyRendered(source,state,root=false){
523
506
  clone.selected=source.selected;
524
507
  }
525
508
  if(!['img','svg','video','audio','input','canvas'].includes(name)){
526
- for(const [property,value] of [
527
- ['height','auto'],['min-height','0'],['max-height','none'],
528
- ['width','auto'],['min-width','0'],['max-width','100%'],['overflow','visible'],
529
- ['contain','none'],['content-visibility','visible'],['grid-template-rows','none'],
530
- ['break-inside','auto']
531
- ]){
532
- clone.style.setProperty(property,value);
533
- }
534
- }else if(name==='img'||name==='canvas'){
535
- clone.style.setProperty('max-width','100%');
536
- clone.style.setProperty('height','auto');
509
+ clone.setAttribute('data-arcane-print-expand','');
537
510
  }
538
511
  if(['absolute','fixed','sticky'].includes(appearance.position)){
539
- clone.style.setProperty('position','static');
512
+ clone.setAttribute('data-arcane-print-static','');
540
513
  }
541
514
  if(root||name==='iframe'){
542
515
  clone.hidden=false;
543
- clone.style.setProperty('display',appearance.display==='none'?'block':appearance.display);
544
- clone.style.setProperty('visibility','visible');
545
- }
546
- if(name==='pre'){
547
- clone.style.setProperty('white-space','pre-wrap');
548
- clone.style.setProperty('overflow-wrap','anywhere');
549
- }
550
- if(name==='table'){
551
- clone.style.setProperty('table-layout','auto');
552
- }
553
- if(name==='td'||name==='th'){
554
- clone.style.setProperty('overflow-wrap','anywhere');
555
- clone.style.setProperty('white-space','normal');
516
+ clone.setAttribute('data-arcane-print-root','');
517
+ if(appearance.display==='none'){
518
+ clone.setAttribute('data-arcane-print-block','');
519
+ }
556
520
  }
557
521
  if(name==='iframe'){
558
522
  const embedded=frameDocument(source);