Wiki source code of Collaboration Setup

Version 4.13 by Veronika Kocher on Thursday, 03 Sep 2026 15:54

Show last authors
1 Set up shared working environments, accounts, access groups, roles and handover processes for projects involving several people.
2
3 == Overview ==
4
5 A shared working environment prevents access, files and responsibilities from depending on individual people. Decide early which systems the team will use, who may access what, and how handovers will be organised.
6
7 == What you need to know ==
8
9 * Use institutional accounts and clearly defined access groups wherever possible.
10 * Assign access rights according to tasks and review them when roles change.
11 * Plan the handover of files, accounts, permissions and responsibilities from the beginning.
12
13 == What you need to do ==
14
15 1. Check what applies to your project.
16 2. Document the relevant decisions.
17 3. Use appropriate institutional services and support where needed.
18
19 == Key questions ==
20
21 * What needs to be decided?
22 * Who is responsible?
23 * What needs to be documented?
24 * Are there legal, ethical or technical constraints?
25 * What needs to happen before the next project phase?
26
27 == Services & Tools ==
28
29 Use the institutional services, infrastructure and tools that fit your project and its requirements. Specific links will be added as the relevant services are included in the Navigator.
30
31 == Info Sheets & Checklists ==
32
33 Relevant Info Sheets, checklists and templates will be added here as they become available.
34
35 == Tutorials ==
36
37
38 {{html}}<span data-arsn-coming-soon="true" style="display:inline-block;margin:6px 0 8px 0;padding:4px 9px;border-radius:14px;background:#fff4ee;border:1px solid #efd9cc;color:#8a4d36;font-size:11px;font-weight:700;letter-spacing:.065em;line-height:1.2;">COMING SOON</span>{{/html}}
39 Step-by-step tutorials will be added here as they become available.
40
41 == Related Topics ==
42
43 Further guidance can be found in the adjacent phases Prepare, Work & Manage and Publish & Share.
44
45 == Who is responsible? ==
46
47
48 {{info title="Service routing"}}
49 **Primary specialist service(s):** Project/host unit for roles and working agreements; IT & Digitalisation/ZID for accounts and shared working environments; Legal for formal cooperation agreements where required.
50
51 **Role of Support Kunst und Forschung (SKF):** Coordinates partners, proposal/project routes and project-level handover dependencies in funded research projects.
52 {{/info}}
53
54 If you are unsure which route applies, start with the specialist service named above. For funded or project-based research involving several units, SKF can coordinate the project route.
55
56 {{html}}
57 <!-- ARSN_SEARCH_TERMS_START -->
58 <details class="arsn-search-terms" style="margin-top:28px;padding-top:10px;border-top:1px solid #eee;">
59 <summary style="cursor:pointer;color:#666;font-size:13px;">Search terms &amp; related topics</summary>
60 <div style="margin-top:9px;color:#555;font-size:13px;">
61 <p style="margin:0 0 8px 0;">
62 This topic can also be found through related terms, synonyms and common search queries.
63 Select a term to search the Art &amp; Research Services Navigator.
64 </p>
65 <p style="margin:0;"><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=art%20and%20research#arsn-search-input" class="arsn-search-term" data-search-term="art and research" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">art and research</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=prepare#arsn-search-input" class="arsn-search-term" data-search-term="prepare" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">prepare</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=collaboration#arsn-search-input" class="arsn-search-term" data-search-term="collaboration" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">collaboration</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=data%20exchange#arsn-search-input" class="arsn-search-term" data-search-term="data exchange" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">data exchange</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=shared%20workspace#arsn-search-input" class="arsn-search-term" data-search-term="shared workspace" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">shared workspace</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=accounts#arsn-search-input" class="arsn-search-term" data-search-term="accounts" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">accounts</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=access%20groups#arsn-search-input" class="arsn-search-term" data-search-term="access groups" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">access groups</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=roles%20and%20responsibilities#arsn-search-input" class="arsn-search-term" data-search-term="roles and responsibilities" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">roles and responsibilities</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=handover#arsn-search-input" class="arsn-search-term" data-search-term="handover" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">handover</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=team%20collaboration#arsn-search-input" class="arsn-search-term" data-search-term="team collaboration" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">team collaboration</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=project%20partners#arsn-search-input" class="arsn-search-term" data-search-term="project partners" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">project partners</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=shared%20folder#arsn-search-input" class="arsn-search-term" data-search-term="shared folder" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">shared folder</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=shared%20accounts#arsn-search-input" class="arsn-search-term" data-search-term="shared accounts" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">shared accounts</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=collaborative%20working#arsn-search-input" class="arsn-search-term" data-search-term="collaborative working" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">collaborative working</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=zusammenarbeit#arsn-search-input" class="arsn-search-term" data-search-term="zusammenarbeit" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">zusammenarbeit</a><a href="https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/?q=datenaustausch#arsn-search-input" class="arsn-search-term" data-search-term="datenaustausch" style="display:inline-block;margin:3px 5px 3px 0;padding:3px 8px;border:1px solid #d7d7d7;border-radius:14px;background:#fff;color:#333;text-decoration:none;font-size:12px;">datenaustausch</a></p>
66 </div>
67 </details>
68 <!-- ARSN_SEARCH_TERMS_END -->
69 {{/html}}
70
71 {{html clean="false"}}
72 <!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
73
74 <style data-sn-service-navigator-master="1">
75 /* =========================================================
76 MASTER TYPOGRAPHY
77 ========================================================= */
78 #xwikicontent h1,
79 #xwikicontent h2,
80 #xwikicontent h3,
81 #xwikicontent h4,
82 #xwikicontent h5,
83 #xwikicontent h6,
84 #xwikicontent .box-title,
85 #xwikicontent [role="heading"],
86 #xwikicontent h1 a,
87 #xwikicontent h2 a,
88 #xwikicontent h3 a,
89 #xwikicontent h4 a,
90 #xwikicontent h5 a,
91 #xwikicontent h6 a,
92 #xwikicontent .box-title a,
93 #xwikicontent [role="heading"] a{
94 text-align:left!important;
95 text-justify:auto!important;
96 word-spacing:normal!important;
97 }
98
99 /* =========================================================
100 COMING SOON / IN VORBEREITUNG
101 ========================================================= */
102 .sn-coming-soon-badge{
103 display:inline-block;
104 vertical-align:middle;
105 margin-left:10px;
106 padding:4px 8px;
107 border-radius:14px;
108 border:1px solid #efd9cc;
109 background:#fff4ee;
110 color:#8a4d36;
111 font-size:11px;
112 font-weight:700;
113 letter-spacing:.055em;
114 line-height:1.2;
115 white-space:nowrap;
116 }
117
118 /* =========================================================
119 NATIVE / DETAIL CALLOUT GEOMETRY
120 Preserve existing backgrounds.
121 ========================================================= */
122 #xwikicontent .arsn-info,
123 #xwikicontent .dmp-info,
124 #xwikicontent .ido-info,
125 #xwikicontent .pp-info,
126 #xwikicontent .infomessage{
127 box-sizing:border-box!important;
128 border-left:4px solid #21b6d7!important;
129 border-radius:8px;
130 text-align:left!important;
131 word-spacing:normal!important;
132 }
133
134 #xwikicontent .arsn-warn,
135 #xwikicontent .dmp-warn,
136 #xwikicontent .ido-warn,
137 #xwikicontent .pp-warn,
138 #xwikicontent .warn,
139 #xwikicontent .warning,
140 #xwikicontent .warningmessage,
141 #xwikicontent .errormessage{
142 box-sizing:border-box!important;
143 border-left:4px solid #e94b13!important;
144 border-radius:8px;
145 text-align:left!important;
146 word-spacing:normal!important;
147 }
148
149 [data-sn-master-equal-height],
150 [data-sn-master-first-row]{
151 box-sizing:border-box;
152 }
153
154 /* =========================================================
155 FULL-WIDTH THREE-LINE NUMBER / TITLE / SUBTITLE BLOCKS
156 ========================================================= */
157 #xwikicontent .arsn-area-label[data-sn-three-line="1"]{
158 display:grid!important;
159 grid-template-columns:minmax(0,1fr)!important;
160 grid-auto-rows:auto!important;
161 width:100%!important;
162 max-width:none!important;
163 box-sizing:border-box!important;
164 justify-items:start!important;
165 align-items:start!important;
166 gap:2px!important;
167 text-align:left!important;
168 text-align-last:left!important;
169 text-justify:auto!important;
170 word-spacing:normal!important;
171 white-space:normal!important;
172 }
173 #xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-number,
174 #xwikicontent .arsn-area-label[data-sn-three-line="1"] > .sn-area-label-title,
175 #xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-action{
176 display:block!important;
177 width:100%!important;
178 margin:0!important;
179 text-align:left!important;
180 text-align-last:left!important;
181 text-justify:auto!important;
182 word-spacing:normal!important;
183 white-space:normal!important;
184 }
185 </style>
186
187 <script data-sn-service-navigator-master="1">
188 (function(){
189 "use strict";
190
191 var PAGE_KIND="detail";
192 var PLACEHOLDER=true;
193 var PLACEHOLDER_LABEL="COMING SOON";
194
195 var MOBILE_MAX=767;
196 var ROW_TOLERANCE=6;
197 var RESIZE_DEBOUNCE=220;
198
199 var root=
200 document.getElementById("xwikicontent")||
201 document.querySelector(".xwiki-rendering-content")||
202 document.querySelector("main")||
203 document.body;
204
205 if(!root)return;
206
207 var managedHeight=new Set();
208 var managedMargin=new Set();
209 var originalHeight=new WeakMap();
210 var originalMargin=new WeakMap();
211
212 var resizeTimer=0;
213 var running=false;
214
215 var THEMES=[
216 {
217 name:"BLUE",
218 accent:"#21b6d7",
219 bg:"#eaf7fb",
220 text:"#315d68",
221 labels:[
222 "HIER STARTEN",
223 "ENTSCHEIDEN",
224 "ÜBERPRÜFEN & ANPASSEN",
225 "START HERE",
226 "DECIDE",
227 "REVIEW & ADAPT"
228 ]
229 },
230 {
231 name:"RED",
232 accent:"#e94b13",
233 bg:"#fff1ec",
234 text:"#8a4d36",
235 labels:[
236 "PLANEN & ORGANISIEREN",
237 "ORGANISIEREN & DOKUMENTIEREN",
238 "PUBLIZIEREN & PRÄSENTIEREN",
239 "PLAN & ORGANISE",
240 "PLAN & ORGANIZE",
241 "ORGANISE & DOCUMENT",
242 "ORGANIZE & DOCUMENT",
243 "PUBLISH & PRESENT"
244 ]
245 },
246 {
247 name:"YELLOW",
248 accent:"#f0aa00",
249 bg:"#fff8e7",
250 text:"#785b17",
251 labels:[
252 "SCHÜTZEN & KLÄREN",
253 "STANDARDISIEREN & IDENTIFIZIEREN",
254 "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN",
255 "PROTECT & CLARIFY",
256 "STANDARDISE & IDENTIFY",
257 "STANDARDIZE & IDENTIFY",
258 "OPEN, REUSE & MAKE FINDABLE"
259 ]
260 },
261 {
262 name:"GREEN",
263 accent:"#38b76a",
264 bg:"#edf9f1",
265 text:"#3f7451",
266 labels:[
267 "INFRASTRUKTUR EINRICHTEN",
268 "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN",
269 "SPEICHERN & ZUGRIFF STEUERN",
270 "REPOSITORIUM, ERHALTEN & ÜBERGEBEN",
271 "SET UP INFRASTRUCTURE",
272 "SET UP INFRASTRUCTURE & COLLABORATION",
273 "STORE & CONTROL ACCESS",
274 "REPOSITORY, PRESERVE & HAND OVER"
275 ]
276 }
277 ];
278
279 function num(value){
280 var n=parseFloat(value);
281 return Number.isFinite(n)?n:0;
282 }
283
284 function norm(value){
285 return String(value||"")
286 .replace(/\s+/g," ")
287 .trim()
288 .toUpperCase();
289 }
290
291 function visible(el){
292 if(!el||el.nodeType!==1)return false;
293
294 var style=getComputedStyle(el);
295 var rect=el.getBoundingClientRect();
296
297 return (
298 style.display!=="none"&&
299 style.visibility!=="hidden"&&
300 rect.width>20&&
301 rect.height>4
302 );
303 }
304
305 function saveStyle(el,map,property){
306 if(map.has(el))return;
307
308 map.set(el,{
309 value:el.style.getPropertyValue(property),
310 priority:el.style.getPropertyPriority(property)
311 });
312 }
313
314 function restoreStyle(el,map,property){
315 var original=map.get(el);
316
317 if(original&&original.value){
318 el.style.setProperty(
319 property,
320 original.value,
321 original.priority||""
322 );
323 }else{
324 el.style.removeProperty(property);
325 }
326 }
327
328 function resetRuntime(){
329 managedHeight.forEach(function(el){
330 restoreStyle(
331 el,
332 originalHeight,
333 "min-height"
334 );
335 el.removeAttribute(
336 "data-sn-master-equal-height"
337 );
338 });
339
340 managedMargin.forEach(function(el){
341 restoreStyle(
342 el,
343 originalMargin,
344 "margin-top"
345 );
346 el.removeAttribute(
347 "data-sn-master-first-row"
348 );
349 });
350
351 managedHeight.clear();
352 managedMargin.clear();
353 }
354
355 function themeFor(text){
356 var value=norm(text);
357
358 for(var i=0;i<THEMES.length;i++){
359 for(var j=0;j<THEMES[i].labels.length;j++){
360 var label=THEMES[i].labels[j];
361
362 if(
363 value===label||
364 value.indexOf(label+" ")===0||
365 value.indexOf(label+" -")===0||
366 value.indexOf(label+" ·")===0
367 ){
368 return THEMES[i];
369 }
370 }
371 }
372
373 return null;
374 }
375
376 /* =======================================================
377 BORDERLESS FILLED RED/ORANGE CTA BUTTONS
378 ======================================================= */
379
380 function colourDistance(a,b){
381 return Math.sqrt(
382 Math.pow(a[0]-b[0],2)+
383 Math.pow(a[1]-b[1],2)+
384 Math.pow(a[2]-b[2],2)
385 );
386 }
387
388 function makeFilledRedOrangeCTAsBorderless(){
389 var RED_ORANGE=[233,75,19];
390
391 Array.from(
392 root.querySelectorAll(
393 'a,button,[role="button"],input[type="submit"],input[type="button"]'
394 )
395 ).forEach(function(el){
396 if(!visible(el))return;
397
398 var style=getComputedStyle(el);
399 var rgb=parseRGB(style.backgroundColor);
400
401 if(!rgb)return;
402
403 if(
404 colourDistance(
405 rgb,
406 RED_ORANGE
407 )>55
408 ){
409 return;
410 }
411
412 var rect=el.getBoundingClientRect();
413
414 if(
415 rect.width<80||
416 rect.height<24
417 ){
418 return;
419 }
420
421 el.style.setProperty(
422 "border",
423 "none",
424 "important"
425 );
426
427 el.style.setProperty(
428 "border-left",
429 "none",
430 "important"
431 );
432
433 el.style.setProperty(
434 "border-top",
435 "none",
436 "important"
437 );
438
439 el.style.setProperty(
440 "border-right",
441 "none",
442 "important"
443 );
444
445 el.style.setProperty(
446 "border-bottom",
447 "none",
448 "important"
449 );
450
451 el.style.setProperty(
452 "box-shadow",
453 "none",
454 "important"
455 );
456 });
457 }
458
459 /* =======================================================
460 FULL-WIDTH THREE-LINE AREA LABELS
461 ======================================================= */
462
463 function compactText(value){
464 return String(value||"")
465 .replace(/\s+/g," ")
466 .trim();
467 }
468
469 function makeThreeLineAreaLabels(){
470 Array.from(
471 root.querySelectorAll(
472 ".arsn-area-label"
473 )
474 ).forEach(function(label){
475 if(
476 label.getAttribute(
477 "data-sn-three-line"
478 )==="1"
479 ){
480 return;
481 }
482
483 var number=
484 label.querySelector(
485 ":scope > .arsn-area-number"
486 );
487
488 var action=
489 label.querySelector(
490 ":scope > .arsn-area-action"
491 );
492
493 if(
494 !number||
495 !action
496 ){
497 return;
498 }
499
500 var clone=
501 label.cloneNode(true);
502
503 var cloneNumber=
504 clone.querySelector(
505 ":scope > .arsn-area-number"
506 );
507
508 var cloneAction=
509 clone.querySelector(
510 ":scope > .arsn-area-action"
511 );
512
513 if(cloneNumber){
514 cloneNumber.remove();
515 }
516
517 if(cloneAction){
518 cloneAction.remove();
519 }
520
521 var titleText=
522 compactText(
523 clone.textContent
524 );
525
526 if(!titleText){
527 return;
528 }
529
530 var numberNode=
531 number.cloneNode(true);
532
533 var actionNode=
534 action.cloneNode(true);
535
536 var titleNode=
537 document.createElement(
538 "span"
539 );
540
541 titleNode.className=
542 "sn-area-label-title";
543
544 titleNode.textContent=
545 titleText;
546
547 while(label.firstChild){
548 label.removeChild(
549 label.firstChild
550 );
551 }
552
553 label.appendChild(
554 numberNode
555 );
556
557 label.appendChild(
558 titleNode
559 );
560
561 label.appendChild(
562 actionNode
563 );
564
565 label.setAttribute(
566 "data-sn-three-line",
567 "1"
568 );
569
570 var head=
571 label.closest(
572 ".arsn-area-head"
573 );
574
575 if(head){
576 head.style.setProperty(
577 "width",
578 "100%",
579 "important"
580 );
581
582 head.style.setProperty(
583 "max-width",
584 "100%",
585 "important"
586 );
587
588 head.style.setProperty(
589 "box-sizing",
590 "border-box",
591 "important"
592 );
593 }
594 });
595 }
596
597 /* =======================================================
598 PLACEHOLDER BADGE
599 ======================================================= */
600
601 function applyPlaceholderBadge(){
602 if(!PLACEHOLDER)return;
603
604 if(
605 document.querySelector(
606 ".sn-coming-soon-badge"
607 )
608 ){
609 return;
610 }
611
612 var title=
613 document.querySelector(
614 "#document-title"
615 )||
616 document.querySelector(
617 "h1"
618 );
619
620 if(!title)return;
621
622 var badge=
623 document.createElement(
624 "span"
625 );
626
627 badge.className=
628 "sn-coming-soon-badge";
629
630 badge.textContent=
631 PLACEHOLDER_LABEL;
632
633 badge.setAttribute(
634 "aria-label",
635 PLACEHOLDER_LABEL
636 );
637
638 title.appendChild(
639 badge
640 );
641 }
642
643 /* =======================================================
644 DETAIL PAGE OWN-ACCENT PROPAGATION
645 ======================================================= */
646
647 function parseRGB(value){
648 var match=String(value||"").match(
649 /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
650 );
651
652 if(!match)return null;
653
654 return [
655 Number(match[1]),
656 Number(match[2]),
657 Number(match[3])
658 ];
659 }
660
661 function distance(a,b){
662 return Math.sqrt(
663 Math.pow(a[0]-b[0],2)+
664 Math.pow(a[1]-b[1],2)+
665 Math.pow(a[2]-b[2],2)
666 );
667 }
668
669 function paletteMatch(cssColor){
670 var rgb=parseRGB(cssColor);
671
672 if(!rgb)return null;
673
674 var palette=[
675 {hex:"#21b6d7",rgb:[33,182,215]},
676 {hex:"#e94b13",rgb:[233,75,19]},
677 {hex:"#f0aa00",rgb:[240,170,0]},
678 {hex:"#38b76a",rgb:[56,183,106]}
679 ];
680
681 var best=null;
682 var bestDistance=Infinity;
683
684 palette.forEach(function(item){
685 var d=distance(rgb,item.rgb);
686
687 if(d<bestDistance){
688 best=item;
689 bestDistance=d;
690 }
691 });
692
693 return bestDistance<=30
694 ?best
695 :null;
696 }
697
698 function propagateDetailAccents(){
699 if(PAGE_KIND!=="detail")return;
700
701 Array.from(
702 root.querySelectorAll(
703 ".arsn-call,.dmp-call,.ido-call,.pp-call,"+
704 ".arsn-source,.dmp-source,.ido-source,.pp-source"
705 )
706 ).forEach(function(el){
707 if(!visible(el))return;
708
709 var style=getComputedStyle(el);
710
711 if(
712 num(style.borderTopWidth)>=2
713 ){
714 var match=
715 paletteMatch(
716 style.borderTopColor
717 );
718
719 if(match){
720 el.style.setProperty(
721 "border-left",
722 "4px solid "+match.hex,
723 "important"
724 );
725 }
726 }
727 });
728
729 // Warning families: explicit safety override.
730 Array.from(
731 root.querySelectorAll(
732 ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+
733 ".warn,.warning,.warningmessage,.errormessage"
734 )
735 ).forEach(function(el){
736 if(!visible(el))return;
737
738 el.style.setProperty(
739 "border-left",
740 "4px solid #e94b13",
741 "important"
742 );
743 });
744
745 // Info families: explicit orientation override.
746 Array.from(
747 root.querySelectorAll(
748 ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage"
749 )
750 ).forEach(function(el){
751 if(!visible(el))return;
752
753 el.style.setProperty(
754 "border-left",
755 "4px solid #21b6d7",
756 "important"
757 );
758 });
759 }
760
761 /* =======================================================
762 OVERVIEW SEMANTIC THEME PALETTE
763 ======================================================= */
764
765 function smallestThemeHeaders(){
766 return Array.from(
767 root.querySelectorAll(
768 "div,span,p,strong,h3,h4,h5,h6"
769 )
770 ).filter(function(el){
771 if(!visible(el))return false;
772 if(!themeFor(el.textContent))return false;
773
774 return !Array.from(
775 el.children||[]
776 ).some(function(child){
777 return !!themeFor(
778 child.textContent
779 );
780 });
781 });
782 }
783
784 function findOverviewCard(header){
785 var node=header.parentElement;
786 var candidates=[];
787
788 while(node&&node!==root){
789 var rect=node.getBoundingClientRect();
790 var style=getComputedStyle(node);
791
792 var border=
793 num(style.borderTopWidth)+
794 num(style.borderRightWidth)+
795 num(style.borderBottomWidth)+
796 num(style.borderLeftWidth);
797
798 if(
799 rect.width>=220&&
800 rect.width<=800&&
801 rect.height>=120&&
802 border>=1
803 ){
804 candidates.push(node);
805 }
806
807 node=node.parentElement;
808 }
809
810 if(!candidates.length)return null;
811
812 candidates.sort(function(a,b){
813 return (
814 b.getBoundingClientRect().height-
815 a.getBoundingClientRect().height
816 );
817 });
818
819 return candidates[0];
820 }
821
822 function rowCandidates(link,card){
823 var result=[];
824 var cardRect=
825 card.getBoundingClientRect();
826
827 var node=link;
828
829 while(node&&node!==card){
830 if(visible(node)){
831 var rect=
832 node.getBoundingClientRect();
833
834 if(
835 rect.height<=105&&
836 rect.width>=
837 cardRect.width*.50&&
838 rect.width<=
839 cardRect.width*1.03
840 ){
841 result.push(node);
842 }
843 }
844
845 node=node.parentElement;
846 }
847
848 return result;
849 }
850
851 function chooseOuterRow(
852 candidates,
853 link
854 ){
855 if(!candidates.length){
856 return link;
857 }
858
859 var bordered=
860 candidates.filter(function(el){
861 return (
862 num(
863 getComputedStyle(el)
864 .borderLeftWidth
865 )>=1
866 );
867 });
868
869 var pool=
870 bordered.length
871 ?bordered
872 :candidates;
873
874 pool.sort(function(a,b){
875 var ar=
876 a.getBoundingClientRect();
877
878 var br=
879 b.getBoundingClientRect();
880
881 return (
882 ar.left-br.left||
883 br.width-ar.width
884 );
885 });
886
887 return pool[0]||link;
888 }
889
890 function applyOverviewPalette(){
891 if(PAGE_KIND!=="overview"){
892 return [];
893 }
894
895 var headers=
896 smallestThemeHeaders()
897 .map(function(el){
898 return {
899 el:el,
900 theme:
901 themeFor(
902 el.textContent
903 ),
904 card:
905 findOverviewCard(
906 el
907 )
908 };
909 })
910 .filter(function(row){
911 return !!row.card;
912 });
913
914 var unique=[];
915 var seenHeaders=new Set();
916
917 headers.forEach(function(row){
918 var key=
919 row.theme.name+
920 "|"+
921 Math.round(
922 row.card
923 .getBoundingClientRect()
924 .left
925 )+
926 "|"+
927 Math.round(
928 row.el
929 .getBoundingClientRect()
930 .top
931 );
932
933 if(!seenHeaders.has(key)){
934 seenHeaders.add(key);
935 unique.push(row);
936 }
937 });
938
939 unique.forEach(function(row){
940 var headerRect=
941 row.el
942 .getBoundingClientRect();
943
944 row.el.style.setProperty(
945 "background",
946 row.theme.bg,
947 "important"
948 );
949
950 row.el.style.setProperty(
951 "color",
952 row.theme.text,
953 "important"
954 );
955
956 row.el.style.setProperty(
957 "text-align",
958 "left",
959 "important"
960 );
961
962 row.el.style.setProperty(
963 "word-spacing",
964 "normal",
965 "important"
966 );
967
968 var later=
969 unique
970 .filter(function(other){
971 return (
972 other.card===row.card&&
973 other.el
974 .getBoundingClientRect()
975 .top>
976 headerRect.top+2
977 );
978 })
979 .sort(function(a,b){
980 return (
981 a.el
982 .getBoundingClientRect()
983 .top-
984 b.el
985 .getBoundingClientRect()
986 .top
987 );
988 });
989
990 var stopTop=
991 later.length
992 ?later[0].el
993 .getBoundingClientRect()
994 .top
995 :Infinity;
996
997 Array.from(
998 row.card.querySelectorAll("a")
999 ).forEach(function(link){
1000 if(!visible(link))return;
1001
1002 var rect=
1003 link.getBoundingClientRect();
1004
1005 if(
1006 rect.top<=
1007 headerRect.bottom-2||
1008 rect.top>=
1009 stopTop-2
1010 ){
1011 return;
1012 }
1013
1014 var candidates=
1015 rowCandidates(
1016 link,
1017 row.card
1018 );
1019
1020 var target=
1021 chooseOuterRow(
1022 candidates,
1023 link
1024 );
1025
1026 candidates.forEach(function(el){
1027 el.style.setProperty(
1028 "border-left",
1029 "0 solid transparent",
1030 "important"
1031 );
1032 });
1033
1034 target.style.setProperty(
1035 "border-left",
1036 "3px solid "+
1037 row.theme.accent,
1038 "important"
1039 );
1040
1041 target.style.setProperty(
1042 "box-sizing",
1043 "border-box",
1044 "important"
1045 );
1046 });
1047 });
1048
1049 return unique;
1050 }
1051
1052 /* =======================================================
1053 OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1054 ======================================================= */
1055
1056 function alignOverviewCards(headers){
1057 if(
1058 PAGE_KIND!=="overview"||
1059 window.innerWidth<=MOBILE_MAX
1060 ){
1061 return;
1062 }
1063
1064 var cards=[];
1065 var seen=new Set();
1066
1067 headers.forEach(function(row){
1068 if(!seen.has(row.card)){
1069 seen.add(row.card);
1070 cards.push(row.card);
1071 }
1072 });
1073
1074 if(cards.length<2){
1075 return;
1076 }
1077
1078 // Group cards by actual top position.
1079 var groups=[];
1080
1081 cards.forEach(function(card){
1082 var top=
1083 card.getBoundingClientRect().top;
1084
1085 var group=null;
1086
1087 for(var i=0;i<groups.length;i++){
1088 if(
1089 Math.abs(
1090 groups[i].top-top
1091 )<=ROW_TOLERANCE
1092 ){
1093 group=groups[i];
1094 break;
1095 }
1096 }
1097
1098 if(!group){
1099 group={
1100 top:top,
1101 cards:[]
1102 };
1103 groups.push(group);
1104 }
1105
1106 group.cards.push(card);
1107 });
1108
1109 groups.forEach(function(group){
1110 if(group.cards.length<2){
1111 return;
1112 }
1113
1114 var firstHeaders=
1115 group.cards.map(function(card){
1116 var candidates=
1117 headers
1118 .filter(function(row){
1119 return row.card===card;
1120 })
1121 .sort(function(a,b){
1122 return (
1123 a.el
1124 .getBoundingClientRect()
1125 .top-
1126 b.el
1127 .getBoundingClientRect()
1128 .top
1129 );
1130 });
1131
1132 return candidates.length
1133 ?candidates[0]
1134 :null;
1135 });
1136
1137 if(
1138 !firstHeaders.some(function(row){
1139 return !row;
1140 })
1141 ){
1142 var targetTop=
1143 Math.max.apply(
1144 Math,
1145 firstHeaders.map(function(row){
1146 return (
1147 row.el
1148 .getBoundingClientRect()
1149 .top-
1150 row.card
1151 .getBoundingClientRect()
1152 .top
1153 );
1154 })
1155 );
1156
1157 firstHeaders.forEach(function(row){
1158 var relativeTop=
1159 row.el
1160 .getBoundingClientRect()
1161 .top-
1162 row.card
1163 .getBoundingClientRect()
1164 .top;
1165
1166 var delta=
1167 targetTop-relativeTop;
1168
1169 if(delta>1){
1170 saveStyle(
1171 row.el,
1172 originalMargin,
1173 "margin-top"
1174 );
1175
1176 var current=
1177 num(
1178 getComputedStyle(
1179 row.el
1180 ).marginTop
1181 );
1182
1183 row.el.style.setProperty(
1184 "margin-top",
1185 (
1186 current+delta
1187 )+"px"
1188 );
1189
1190 row.el.setAttribute(
1191 "data-sn-master-first-row",
1192 "1"
1193 );
1194
1195 managedMargin.add(
1196 row.el
1197 );
1198 }
1199 });
1200 }
1201
1202 var maxHeight=0;
1203
1204 group.cards.forEach(function(card){
1205 maxHeight=
1206 Math.max(
1207 maxHeight,
1208 card
1209 .getBoundingClientRect()
1210 .height
1211 );
1212 });
1213
1214 maxHeight=
1215 Math.ceil(maxHeight);
1216
1217 group.cards.forEach(function(card){
1218 saveStyle(
1219 card,
1220 originalHeight,
1221 "min-height"
1222 );
1223
1224 card.style.setProperty(
1225 "min-height",
1226 maxHeight+"px"
1227 );
1228
1229 card.setAttribute(
1230 "data-sn-master-equal-height",
1231 "1"
1232 );
1233
1234 managedHeight.add(
1235 card
1236 );
1237 });
1238 });
1239 }
1240
1241 /* =======================================================
1242 DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY
1243 ======================================================= */
1244
1245 function equaliseDetailGrids(){
1246 if(
1247 PAGE_KIND!=="detail"||
1248 window.innerWidth<=MOBILE_MAX
1249 ){
1250 return;
1251 }
1252
1253 var selectors=[
1254 ".arsn-grid",
1255 ".arsn-grid-2",
1256 ".arsn-grid-3",
1257 ".dmp-grid",
1258 ".ido-grid",
1259 ".pp-grid"
1260 ];
1261
1262 selectors.forEach(function(selector){
1263 Array.from(
1264 root.querySelectorAll(selector)
1265 ).forEach(function(grid){
1266 var children=
1267 Array.from(
1268 grid.children||[]
1269 ).filter(visible);
1270
1271 if(children.length<2){
1272 return;
1273 }
1274
1275 var groups=[];
1276
1277 children.forEach(function(child){
1278 var top=
1279 child
1280 .getBoundingClientRect()
1281 .top;
1282
1283 var group=null;
1284
1285 for(var i=0;i<groups.length;i++){
1286 if(
1287 Math.abs(
1288 groups[i].top-top
1289 )<=ROW_TOLERANCE
1290 ){
1291 group=groups[i];
1292 break;
1293 }
1294 }
1295
1296 if(!group){
1297 group={
1298 top:top,
1299 items:[]
1300 };
1301 groups.push(group);
1302 }
1303
1304 group.items.push(child);
1305 });
1306
1307 groups.forEach(function(group){
1308 if(group.items.length<2){
1309 return;
1310 }
1311
1312 var maxHeight=0;
1313
1314 group.items.forEach(function(item){
1315 maxHeight=
1316 Math.max(
1317 maxHeight,
1318 item
1319 .getBoundingClientRect()
1320 .height
1321 );
1322 });
1323
1324 maxHeight=
1325 Math.ceil(maxHeight);
1326
1327 group.items.forEach(function(item){
1328 saveStyle(
1329 item,
1330 originalHeight,
1331 "min-height"
1332 );
1333
1334 item.style.setProperty(
1335 "min-height",
1336 maxHeight+"px"
1337 );
1338
1339 item.setAttribute(
1340 "data-sn-master-equal-height",
1341 "1"
1342 );
1343
1344 managedHeight.add(item);
1345 });
1346 });
1347 });
1348 });
1349 }
1350
1351 /* =======================================================
1352 RUN / RESPONSIVE SCHEDULING
1353 ======================================================= */
1354
1355 function run(){
1356 if(running)return;
1357
1358 running=true;
1359
1360 try{
1361 resetRuntime();
1362 applyPlaceholderBadge();
1363 propagateDetailAccents();
1364
1365 var headers=
1366 applyOverviewPalette();
1367
1368 makeThreeLineAreaLabels();
1369 makeFilledRedOrangeCTAsBorderless();
1370
1371 if(
1372 window.innerWidth>
1373 MOBILE_MAX
1374 ){
1375 alignOverviewCards(
1376 headers
1377 );
1378
1379 equaliseDetailGrids();
1380 }
1381 }finally{
1382 running=false;
1383 }
1384 }
1385
1386 function onResize(){
1387 if(resizeTimer){
1388 clearTimeout(
1389 resizeTimer
1390 );
1391 }
1392
1393 resizeTimer=
1394 setTimeout(
1395 function(){
1396 resizeTimer=0;
1397 run();
1398 },
1399 RESIZE_DEBOUNCE
1400 );
1401 }
1402
1403 async function waitForReady(){
1404 if(
1405 document.readyState!=="complete"
1406 ){
1407 await new Promise(function(resolve){
1408 window.addEventListener(
1409 "load",
1410 resolve,
1411 {once:true}
1412 );
1413 });
1414 }
1415
1416 if(
1417 document.fonts&&
1418 document.fonts.ready
1419 ){
1420 try{
1421 await document.fonts.ready;
1422 }catch(error){}
1423 }
1424
1425 var images=
1426 Array.from(
1427 root.querySelectorAll("img")
1428 );
1429
1430 await Promise.all(
1431 images.map(function(img){
1432 if(img.complete){
1433 return Promise.resolve();
1434 }
1435
1436 return new Promise(function(resolve){
1437 var done=function(){
1438 resolve();
1439 };
1440
1441 img.addEventListener(
1442 "load",
1443 done,
1444 {once:true}
1445 );
1446
1447 img.addEventListener(
1448 "error",
1449 done,
1450 {once:true}
1451 );
1452 });
1453 })
1454 );
1455
1456 run();
1457 }
1458
1459 window.addEventListener(
1460 "resize",
1461 onResize,
1462 {passive:true}
1463 );
1464
1465 waitForReady();
1466 })();
1467 </script>
1468
1469 <!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
1470 {{/html}}