arcane-os 0.47.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.
@@ -34,7 +34,8 @@
34
34
  user-select: none;
35
35
  }
36
36
 
37
- button:focus-visible {
37
+ button:focus-visible,
38
+ #recognitionLanguage:focus-visible {
38
39
  outline: .2rem solid var(--arcane-focus, var(--focus-color));
39
40
  outline-offset: .18rem;
40
41
  }
@@ -85,6 +86,32 @@
85
86
  min-width: 0;
86
87
  }
87
88
 
89
+ .recognition_language {
90
+ display: flex;
91
+ flex-wrap: wrap;
92
+ align-items: center;
93
+ gap: .35rem .6rem;
94
+ margin-block-end: .35rem;
95
+ font-size: .86rem;
96
+ }
97
+
98
+ .recognition_language[hidden] {
99
+ display: none;
100
+ }
101
+
102
+ #recognitionLanguage {
103
+ box-sizing: border-box;
104
+ width: 10rem;
105
+ max-width: 100%;
106
+ min-height: 2.25rem;
107
+ padding: .35rem .5rem;
108
+ border: 1px solid var(--arcane-border, var(--border-color));
109
+ border-radius: var(--arcane-radius-small, .4rem);
110
+ background: var(--arcane-surface, var(--background-color));
111
+ color: var(--arcane-text, var(--text-color));
112
+ font: inherit;
113
+ }
114
+
88
115
  .speech_status {
89
116
  margin: 0;
90
117
  color: var(--arcane-muted, var(--text-color));
@@ -162,6 +189,25 @@
162
189
  <button id="sttActivationButton" type="button" hidden disabled>Start transcription</button>
163
190
  <button id="stopButton" type="button" class="hidden" disabled>Send</button>
164
191
  <div class="speech_feedback">
192
+ <label id="recognitionLanguageControl" class="recognition_language" hidden>
193
+ Recognition language
194
+ <input id="recognitionLanguage" type="text" list="recognitionLanguages" placeholder="Browser default" title="Recognition language tag, such as en-US or es-MX" autocomplete="off" spellcheck="false">
195
+ <datalist id="recognitionLanguages">
196
+ <option value="en-US">English (United States)</option>
197
+ <option value="en-GB">English (United Kingdom)</option>
198
+ <option value="es-MX">Spanish (Mexico)</option>
199
+ <option value="es-ES">Spanish (Spain)</option>
200
+ <option value="fr-FR">French</option>
201
+ <option value="de-DE">German</option>
202
+ <option value="it-IT">Italian</option>
203
+ <option value="pt-BR">Portuguese (Brazil)</option>
204
+ <option value="ja-JP">Japanese</option>
205
+ <option value="ko-KR">Korean</option>
206
+ <option value="zh-CN">Chinese (Mandarin, mainland China)</option>
207
+ <option value="hi-IN">Hindi</option>
208
+ <option value="ar-SA">Arabic (Saudi Arabia)</option>
209
+ </datalist>
210
+ </label>
165
211
  <p id="speechStatus" class="speech_status" role="status" aria-live="polite"></p>
166
212
  <progress
167
213
  id="sttActivationProgress"
@@ -214,6 +260,7 @@
214
260
  source: 'arcane.component.speech',
215
261
  eventTypes: [
216
262
  'speech-ready',
263
+ 'speech-transcription-progress',
217
264
  'speech-transcription-complete',
218
265
  'speech-transcription-error',
219
266
  'speech-transcription-cancelled',
@@ -232,6 +279,8 @@
232
279
  const stopButton = shadowRoot.querySelector('#stopButton');
233
280
  const muteButton = shadowRoot.querySelector('#muteButton');
234
281
  const speechStatus = shadowRoot.querySelector('#speechStatus');
282
+ const recognitionLanguageControl = shadowRoot.querySelector('#recognitionLanguageControl');
283
+ const recognitionLanguageInput = shadowRoot.querySelector('#recognitionLanguage');
235
284
  const silenceDuration = 0;
236
285
  const runtimeStateAbortController = new AbortController();
237
286
 
@@ -258,6 +307,18 @@
258
307
  let transcriptionOperationId = null;
259
308
  let ttsOperationId = null;
260
309
  let destroyed = false;
310
+ let recognitionLanguage = is.string(host.recognitionLanguage)
311
+ ? host.recognitionLanguage
312
+ : navigator.language || '';
313
+ Object.defineProperty(host, 'recognitionLanguage', {
314
+ configurable: true,
315
+ enumerable: true,
316
+ get: function getRecognitionLanguage() {
317
+ return recognitionLanguage;
318
+ },
319
+ set: setRecognitionLanguage
320
+ });
321
+ recognitionLanguageInput.value = recognitionLanguage;
261
322
 
262
323
  function nextSpeechOperationId(kind) {
263
324
  eventOperationSequence += 1;
@@ -349,6 +410,7 @@
349
410
 
350
411
  const initialMutedWasHydrated = is.boolean(host.initialMuted);
351
412
  host.initialMuted = initialMutedWasHydrated ? host.initialMuted : true;
413
+ host.displayTranscription = host.displayTranscription !== false;
352
414
  host.muted = true;
353
415
  host.configure = configure;
354
416
  host.destroy = destroy;
@@ -396,6 +458,7 @@
396
458
  recordButton.addEventListener('blur', handleRecordBlur, lifecycleListenerOptions);
397
459
  stopButton.addEventListener('click', stop, lifecycleListenerOptions);
398
460
  muteButton.addEventListener('click', muteToggle, lifecycleListenerOptions);
461
+ recognitionLanguageInput.addEventListener('input', updateRecognitionLanguage, lifecycleListenerOptions);
399
462
  window.addEventListener('ai-ready', synchronizeAIReadiness, lifecycleListenerOptions);
400
463
  window.addEventListener(
401
464
  'pagehide',
@@ -477,10 +540,28 @@
477
540
  host.initialMuted = configuredMuted;
478
541
  applyConfiguredMutedState(configuredMuted);
479
542
  }
543
+ if (Object.prototype.hasOwnProperty.call(options, 'recognitionLanguage')) {
544
+ host.recognitionLanguage = options.recognitionLanguage;
545
+ }
546
+ if (Object.prototype.hasOwnProperty.call(options, 'displayTranscription')) {
547
+ host.displayTranscription = options.displayTranscription !== false;
548
+ }
480
549
 
481
550
  return host;
482
551
  }
483
552
 
553
+ function setRecognitionLanguage(language) {
554
+ if (!is.string(language)) {
555
+ throw new TypeError('Recognition language must be a BCP47 language tag string.');
556
+ }
557
+ recognitionLanguage = language;
558
+ recognitionLanguageInput.value = language;
559
+ }
560
+
561
+ function updateRecognitionLanguage() {
562
+ host.recognitionLanguage = recognitionLanguageInput.value;
563
+ }
564
+
484
565
  function updateMicrophoneAvailability(available) {
485
566
  if (destroyed) {
486
567
  return;
@@ -617,6 +698,12 @@
617
698
  }
618
699
 
619
700
  function renderControls() {
701
+ recognitionLanguageControl.hidden = !transcriptionEnabled
702
+ || !providerRuntime.supportsTranscriptionCapture();
703
+ recognitionLanguageInput.disabled = destroyed
704
+ || recordingRequested
705
+ || Boolean(nativeCaptureSession)
706
+ || transcriptionActive;
620
707
  if (!transcriptionEnabled) {
621
708
  recordButton.hidden = true;
622
709
  recordButton.disabled = true;
@@ -764,10 +851,21 @@
764
851
  describeSTTRole()
765
852
  );
766
853
  }
767
- } else if (transcriptionEnabled) {
854
+ } else if (transcriptionEnabled
855
+ && (recognitionLanguageControl.hidden
856
+ || sttRole.state !== 'ready'
857
+ || !host.availability.microphone
858
+ || sttRole.busy
859
+ || sttActivationController.pending)) {
768
860
  messages.push(describeSTTRole());
769
861
  }
770
- messages.push(describeTTSRole());
862
+ if (recognitionLanguageControl.hidden
863
+ || pendingTTSIntent
864
+ || pendingUnmute
865
+ || ['loading', 'unloading', 'error'].includes(ttsRole.state)
866
+ || ttsRole.busy) {
867
+ messages.push(describeTTSRole());
868
+ }
771
869
  if ((transcriptionEnabled && sttRole.state === 'error')
772
870
  || ttsRole.state === 'error') {
773
871
  tone = 'error';
@@ -1490,15 +1588,34 @@
1490
1588
  function displayNativeRecognitionText() {
1491
1589
  if (!currentNativeCapture()) return;
1492
1590
  localStatus = {
1493
- message: session.text.join('') + session.interim || 'Listening. Release to finish.',
1591
+ message: (host.displayTranscription
1592
+ ? session.text.join('') + session.interim
1593
+ : '') || 'Listening. Release to finish.',
1494
1594
  tone: '',
1495
1595
  owner: 'recording',
1496
1596
  generation
1497
1597
  };
1498
1598
  renderStatus();
1599
+ publishNativeRecognitionProgress();
1600
+ }
1601
+ function publishNativeRecognitionProgress() {
1602
+ const text = session.text.join('');
1603
+ dispatchSpeechEvent(
1604
+ 'speech-transcription-progress',
1605
+ {text, interim: session.interim},
1606
+ {
1607
+ operationId,
1608
+ publicDetail: {text, interim: session.interim}
1609
+ }
1610
+ );
1499
1611
  }
1500
1612
  async function finishNativeRecognition(error = null) {
1501
1613
  if (!currentNativeCapture()) return;
1614
+ if (session.interim) {
1615
+ session.interim = '';
1616
+ publishNativeRecognitionProgress();
1617
+ if (!currentNativeCapture()) return;
1618
+ }
1502
1619
  nativeCaptureSession = null;
1503
1620
  recordingRequested = false;
1504
1621
  resetRecordPress();
@@ -1523,9 +1640,11 @@
1523
1640
  session.capture = providerRuntime.createTranscriptionCapture(
1524
1641
  {
1525
1642
  continuous: true,
1643
+ language: recognitionLanguage || undefined,
1526
1644
  onSegment: function retainFinalRecognition(segment) {
1527
1645
  if (!currentNativeCapture()) return;
1528
1646
  session.text.push(segment.text);
1647
+ session.interim = '';
1529
1648
  displayNativeRecognitionText();
1530
1649
  },
1531
1650
  onInterim: function displayInterimRecognition(result) {
@@ -80,9 +80,8 @@
80
80
 
81
81
  <section class="voice-transcription">
82
82
  <p id="description" class="description" part="description"></p>
83
- <section id="transcript" class="transcript" part="transcript"></section>
83
+ <section id="transcript" class="transcript" part="transcript" aria-live="polite"></section>
84
84
  <div class="transcription-feedback">
85
- <p id="interim" class="status" part="interim" aria-live="polite" hidden></p>
86
85
  <p id="status" class="status" part="status" role="status" aria-live="polite"></p>
87
86
  <progress
88
87
  id="sttActivationProgress"
@@ -150,7 +149,6 @@
150
149
  const description=host.shadowRoot.querySelector('#description');
151
150
  const transcriptElement=host.shadowRoot.querySelector('#transcript');
152
151
  const status=host.shadowRoot.querySelector('#status');
153
- const interimElement=host.shadowRoot.querySelector('#interim');
154
152
  const startButton=host.shadowRoot.querySelector('#start');
155
153
  const sttActivationButton=host.shadowRoot.querySelector('#sttActivation');
156
154
  const sttActivationProgress = host.shadowRoot.querySelector('#sttActivationProgress');
@@ -413,13 +411,14 @@
413
411
  stage:is.string(clip.text)?'append':'transcribe',
414
412
  segment:is.string(clip.text)?clip.text:null
415
413
  });
416
- renderInterimRecognition(session);
414
+ if(is.string(clip.text)) session.interim='';
415
+ renderTranscript();
417
416
  processContinuousQueue(session);
418
417
  },
419
418
  onInterim:function displayInterimRecognition(result){
420
419
  if(!isCurrentContinuousSession(session)) return;
421
420
  session.interim=result.text;
422
- renderInterimRecognition(session);
421
+ renderTranscript();
423
422
  },
424
423
  onState:function captureStateChanged(nextState){
425
424
  if(!isCurrentContinuousSession(session)){
@@ -429,7 +428,7 @@
429
428
  if(nextState==='stopped'||nextState==='interrupted'){
430
429
  session.listening=false;
431
430
  session.interim='';
432
- renderInterimRecognition(session);
431
+ renderTranscript();
433
432
  }
434
433
  renderContinuousState(session);
435
434
  settleContinuousDrain(session);
@@ -455,7 +454,7 @@
455
454
  if(!isCurrentContinuousSession(session)) return;
456
455
  session.listening=false;
457
456
  session.interim='';
458
- renderInterimRecognition(session);
457
+ renderTranscript();
459
458
  if(!session.captureError) session.captureState='stopped';
460
459
  renderContinuousState(session);
461
460
  settleContinuousDrain(session);
@@ -508,17 +507,6 @@
508
507
  };
509
508
  }
510
509
 
511
- function renderInterimRecognition(session){
512
- if(!isCurrentContinuousSession(session)) return;
513
- const pending=[];
514
- for(const clip of session.queue){
515
- if(clip.stage==='append') pending.push(clip.segment);
516
- }
517
- const text=pending.join(options.separator)+session.interim;
518
- interimElement.textContent=text;
519
- interimElement.hidden=text.length===0;
520
- }
521
-
522
510
  function renderContinuousState(session){
523
511
  if(!isCurrentContinuousSession(session)){
524
512
  return;
@@ -665,7 +653,6 @@
665
653
  clip.stage='save';
666
654
  transcript=clip.transcript;
667
655
  renderTranscript();
668
- renderInterimRecognition(session);
669
656
  }
670
657
  if(options.persist){
671
658
  const save=options.onSave||(is.function(host.save)?host.save.bind(host):null);
@@ -796,8 +783,7 @@
796
783
  return false;
797
784
  }
798
785
  continuousSession=null;
799
- interimElement.textContent='';
800
- interimElement.hidden=true;
786
+ renderTranscript();
801
787
  session.controller.abort();
802
788
  session.requestController?.abort();
803
789
  session.capture?.cancel();
@@ -1349,7 +1335,19 @@
1349
1335
  }
1350
1336
 
1351
1337
  function renderTranscript(){
1352
- transcriptElement.innerHTML=new MD(transcript).safeRendered;
1338
+ // Display live recognition in the output without committing hypotheses
1339
+ // or letting an earlier save delay later finalized text.
1340
+ let output=transcript;
1341
+ const session=continuousSession;
1342
+ if(session&&isCurrentContinuousSession(session)){
1343
+ for(const clip of session.queue){
1344
+ if(clip.stage==='append'){
1345
+ output=appendTranscription(output,clip.segment,options.separator);
1346
+ }
1347
+ }
1348
+ output=appendTranscription(output,session.interim,options.separator);
1349
+ }
1350
+ transcriptElement.innerHTML=new MD(output).safeRendered;
1353
1351
  transcriptElement.querySelectorAll('a').forEach(
1354
1352
  link=>{
1355
1353
  link.target='_blank';
@@ -1433,7 +1431,7 @@
1433
1431
  session.listening=false;
1434
1432
  session.captureState='interrupted';
1435
1433
  session.interim='';
1436
- renderInterimRecognition(session);
1434
+ renderTranscript();
1437
1435
  }
1438
1436
  if(['completing','complete'].includes(state)){
1439
1437
  renderState();
@@ -1,3 +1,5 @@
1
+ @import url('./print.css');
2
+
1
3
  /* Reusable, progressively enhanced documentation-site layout.
2
4
  * Load after Arcane theme.css and primitives.css.
3
5
  */
@@ -944,38 +946,3 @@ body.static-doc-site{
944
946
  }
945
947
  }
946
948
 
947
- @media print{
948
- .static-site-header,
949
- .static-site-footer,
950
- .static-section-nav,
951
- .static-previous-next,
952
- .static-related,
953
- .static-document__source,
954
- .skip-link{
955
- display:none;
956
- }
957
-
958
- .static-site-main,
959
- .static-site-main--document{
960
- max-inline-size:none;
961
- padding:0;
962
- }
963
-
964
- .static-document-layout{
965
- display:block;
966
- }
967
-
968
- .static-document{
969
- inline-size:100%;
970
- }
971
-
972
- .static-document__content table{
973
- display:table;
974
- overflow:visible;
975
- }
976
-
977
- .static-document__content table :where(code,kbd){
978
- overflow-wrap:anywhere;
979
- word-break:break-word;
980
- }
981
- }
@@ -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
- }