Last modified by Veronika Kocher on Friday, 18 Sep 2026 16:47

From version 39.22
edited by Veronika Kocher
on Thursday, 03 Sep 2026 9:34
Change comment: There is no comment for this version
To version 41.4
edited by Veronika Kocher
on Friday, 04 Sep 2026 14:45
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -2,18 +2,13 @@
2 2  
3 3  The **Art & Research Services Navigator** helps you find the right guidance, services and resources for each stage of your project.
4 4  
5 -{{info title="How responsibilities work"}}
6 -The navigator brings services together around the project lifecycle and the researcher's task. It is a navigation layer across university services, not a separate organisational unit.
5 +{{info title="Support for Your Project:"}}
7 7  
8 -**Support Kunst und Forschung (SKF)** supports project and funding activities — especially project development, funding and calls, proposals, and coordination of funded projects — and, where useful, connects them with the University's relevant services.
7 + **Support Kunst und Forschung (SKF)** provides guidance for projects and grant applications and collaborates with the appropriate university services as needed.
9 9  
10 -Depending on the question, these may include the **University Library / Research Data Management & Repository**, **IT**, **Legal and Data Protection**, **Finance and Personnel**, **Publications and Communication**, **Event Management**, the **International Office** and other services.
11 -
12 -The **institute, department or other host unit** remains the artistic or academic home of the project. The navigator brings these offers together along the project stages so you can start from your need rather than from the organisational chart.
9 + The Navigator guides you through the project phases to the resources and points of contact relevant to your project.
13 13  {{/info}}
14 14  
15 -
16 -
17 17  {{html clean="false"}}
18 18  <section data-arsn-search-block-fix="v5" style="margin:20px 0 26px 0;padding:16px 18px;border:1px solid #e3ded6;border-radius:10px;background:#fcfbf8;box-shadow:0 1px 2px rgba(0,0,0,.035);">
19 19   <h2 style="font-size:20px;margin:0 0 6px 0;color:#35312d;">Search the Art &amp; Research Services Navigator</h2>
... ... @@ -439,9 +439,9 @@
439 439  )))
440 440  )))
441 441  
442 -(% style="padding:0 16px 16px 16px;" %)
437 +(% class="arsn-phase-cta-wrap" style="padding:0 16px 16px 16px;" %)
443 443  (((
444 -[[Explore Enable>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Enable/||class="btn btn-primary btn-block"]]
439 +[[Explore Enable>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Enable/||class="btn btn-primary btn-block arsn-phase-cta"]]
445 445  )))
446 446  )))
447 447  )))
... ... @@ -505,9 +505,9 @@
505 505  )))
506 506  )))
507 507  
508 -(% style="padding:0 16px 16px 16px;" %)
503 +(% class="arsn-phase-cta-wrap" style="padding:0 16px 16px 16px;" %)
509 509  (((
510 -[[Explore Work & Manage>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Work%20%26%20Manage/||class="btn btn-primary btn-block"]]
505 +[[Explore Work & Manage>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Work%20%26%20Manage/||class="btn btn-primary btn-block arsn-phase-cta"]]
511 511  )))
512 512  )))
513 513  )))
... ... @@ -581,9 +581,9 @@
581 581  )))
582 582  )))
583 583  
584 -(% style="padding:0 16px 16px 16px;" %)
579 +(% class="arsn-phase-cta-wrap" style="padding:0 16px 16px 16px;" %)
585 585  (((
586 -[[Explore Publish & Share>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Publish%20%26%20Share/||class="btn btn-primary btn-block"]]
581 +[[Explore Publish & Share>>https://xwiki.uni-ak.ac.at/bin/view/Service%20Navigator/Art%20%26%20Research%20Services%20Navigator/Publish%20%26%20Share/||class="btn btn-primary btn-block arsn-phase-cta"]]
587 587  )))
588 588  )))
589 589  )))
... ... @@ -592,6 +592,20 @@
592 592  
593 593  (% style="margin-top:30px;" %)
594 594  (((
590 +
591 +{{html clean="false"}}
592 +<!-- ARSN_TRAINING_WORKSHOPS_V2_START -->
593 +<section class="arsn-training-workshops" data-arsn-training-workshops="v2" style="margin:27px 0 22px 0;">
594 + <div style="padding:16px 18px;background:#eef8fa;border:1px solid #cfe8ef;border-left:5px solid #21b6d7;border-radius:9px;">
595 + <div style="font-size:12px;font-weight:700;letter-spacing:.075em;text-transform:uppercase;color:#3f6871;margin-bottom:5px;">TRAINING &amp; WORKSHOPS</div>
596 + <h3 style="font-size:20px;line-height:1.3;margin:0 0 7px;color:#35312d;text-align:left;">Training, workshops &amp; consultation sessions</h3>
597 + <p style="margin:0 0 10px;color:#5e5953;line-height:1.55;">Relevant opportunities for this topic will be shown here automatically from the central calendar.</p>
598 + <span data-arsn-coming-soon="true" style="display:inline-block;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>
599 + </div>
600 +</section>
601 +<!-- ARSN_TRAINING_WORKSHOPS_V2_END -->
602 +{{/html}}
603 +
595 595  == Practical resources ==
596 596  
597 597  Use practical resources when you need a concise overview, a step-by-step procedure or a ready-to-use project aid.
... ... @@ -640,23 +640,132 @@
640 640  )))
641 641  
642 642  {{html clean="false"}}
643 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
644 -<style data-sn-horizontal-box-harmonizer="4">
645 -[data-sn-equal-height-managed],
646 -[data-sn-first-section-aligned]{
652 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
653 +
654 +<style data-sn-service-navigator-master="1">
655 +/* =========================================================
656 + MASTER TYPOGRAPHY
657 + ========================================================= */
658 +#xwikicontent h1,
659 +#xwikicontent h2,
660 +#xwikicontent h3,
661 +#xwikicontent h4,
662 +#xwikicontent h5,
663 +#xwikicontent h6,
664 +#xwikicontent .box-title,
665 +#xwikicontent [role="heading"],
666 +#xwikicontent h1 a,
667 +#xwikicontent h2 a,
668 +#xwikicontent h3 a,
669 +#xwikicontent h4 a,
670 +#xwikicontent h5 a,
671 +#xwikicontent h6 a,
672 +#xwikicontent .box-title a,
673 +#xwikicontent [role="heading"] a{
674 + text-align:left!important;
675 + text-justify:auto!important;
676 + word-spacing:normal!important;
677 +}
678 +
679 +/* =========================================================
680 + COMING SOON / IN VORBEREITUNG
681 + ========================================================= */
682 +.sn-coming-soon-badge{
683 + display:inline-block;
684 + vertical-align:middle;
685 + margin-left:10px;
686 + padding:4px 8px;
687 + border-radius:14px;
688 + border:1px solid #efd9cc;
689 + background:#fff4ee;
690 + color:#8a4d36;
691 + font-size:11px;
692 + font-weight:700;
693 + letter-spacing:.055em;
694 + line-height:1.2;
695 + white-space:nowrap;
696 +}
697 +
698 +/* =========================================================
699 + NATIVE / DETAIL CALLOUT GEOMETRY
700 + Preserve existing backgrounds.
701 + ========================================================= */
702 +#xwikicontent .arsn-info,
703 +#xwikicontent .dmp-info,
704 +#xwikicontent .ido-info,
705 +#xwikicontent .pp-info,
706 +#xwikicontent .infomessage{
707 + box-sizing:border-box!important;
708 + border-left:4px solid #21b6d7!important;
709 + border-radius:8px;
710 + text-align:left!important;
711 + word-spacing:normal!important;
712 +}
713 +
714 +#xwikicontent .arsn-warn,
715 +#xwikicontent .dmp-warn,
716 +#xwikicontent .ido-warn,
717 +#xwikicontent .pp-warn,
718 +#xwikicontent .warn,
719 +#xwikicontent .warning,
720 +#xwikicontent .warningmessage,
721 +#xwikicontent .errormessage{
722 + box-sizing:border-box!important;
723 + border-left:4px solid #e94b13!important;
724 + border-radius:8px;
725 + text-align:left!important;
726 + word-spacing:normal!important;
727 +}
728 +
729 +[data-sn-master-equal-height],
730 +[data-sn-master-first-row]{
647 647   box-sizing:border-box;
648 648  }
733 +
734 +/* =========================================================
735 + FULL-WIDTH THREE-LINE NUMBER / TITLE / SUBTITLE BLOCKS
736 + ========================================================= */
737 +#xwikicontent .arsn-area-label[data-sn-three-line="1"]{
738 + display:grid!important;
739 + grid-template-columns:minmax(0,1fr)!important;
740 + grid-auto-rows:auto!important;
741 + width:100%!important;
742 + max-width:none!important;
743 + box-sizing:border-box!important;
744 + justify-items:start!important;
745 + align-items:start!important;
746 + gap:2px!important;
747 + text-align:left!important;
748 + text-align-last:left!important;
749 + text-justify:auto!important;
750 + word-spacing:normal!important;
751 + white-space:normal!important;
752 +}
753 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-number,
754 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .sn-area-label-title,
755 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-action{
756 + display:block!important;
757 + width:100%!important;
758 + margin:0!important;
759 + text-align:left!important;
760 + text-align-last:left!important;
761 + text-justify:auto!important;
762 + word-spacing:normal!important;
763 + white-space:normal!important;
764 +}
649 649  </style>
650 -<script data-sn-horizontal-box-harmonizer="4">
766 +
767 +<script data-sn-service-navigator-master="1">
651 651  (function(){
652 652   "use strict";
653 653  
771 + var PAGE_KIND="overview";
772 + var PLACEHOLDER=false;
773 + var PLACEHOLDER_LABEL="COMING SOON";
774 +
654 654   var MOBILE_MAX=767;
655 655   var ROW_TOLERANCE=6;
656 - var MIN_W=150;
657 - var MIN_H=36;
658 - var MAX_PARENT_CHILDREN=16;
659 - var SEARCH_DEPTH=5;
777 + var RESIZE_DEBOUNCE=220;
660 660  
661 661   var root=
662 662   document.getElementById("xwikicontent")||
... ... @@ -666,93 +666,105 @@
666 666  
667 667   if(!root)return;
668 668  
669 - var heightManaged=new Set();
670 - var sectionManaged=new Set();
671 - var originalMinHeight=new WeakMap();
672 - var originalMarginTop=new WeakMap();
673 - var raf=0;
787 + var managedHeight=new Set();
788 + var managedMargin=new Set();
789 + var originalHeight=new WeakMap();
790 + var originalMargin=new WeakMap();
674 674  
675 - function num(v){
676 - var n=parseFloat(v);
677 - return Number.isFinite(n)?n:0;
678 - }
792 + var resizeTimer=0;
793 + var running=false;
679 679  
680 - function visible(el,minW,minH){
681 - if(!el||el.nodeType!==1)return false;
682 -
683 - var s=getComputedStyle(el);
684 -
685 - if(
686 - s.display==="none"||
687 - s.visibility==="hidden"||
688 - Number(s.opacity)===0
689 - ){
690 - return false;
795 + var THEMES=[
796 + {
797 + name:"BLUE",
798 + accent:"#21b6d7",
799 + bg:"#eaf7fb",
800 + text:"#315d68",
801 + labels:[
802 + "HIER STARTEN",
803 + "ENTSCHEIDEN",
804 + "ÜBERPRÜFEN & ANPASSEN",
805 + "START HERE",
806 + "DECIDE",
807 + "REVIEW & ADAPT"
808 + ]
809 + },
810 + {
811 + name:"RED",
812 + accent:"#e94b13",
813 + bg:"#fff1ec",
814 + text:"#8a4d36",
815 + labels:[
816 + "PLANEN & ORGANISIEREN",
817 + "ORGANISIEREN & DOKUMENTIEREN",
818 + "PUBLIZIEREN & PRÄSENTIEREN",
819 + "PLAN & ORGANISE",
820 + "PLAN & ORGANIZE",
821 + "ORGANISE & DOCUMENT",
822 + "ORGANIZE & DOCUMENT",
823 + "PUBLISH & PRESENT"
824 + ]
825 + },
826 + {
827 + name:"YELLOW",
828 + accent:"#f0aa00",
829 + bg:"#fff8e7",
830 + text:"#785b17",
831 + labels:[
832 + "SCHÜTZEN & KLÄREN",
833 + "STANDARDISIEREN & IDENTIFIZIEREN",
834 + "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN",
835 + "PROTECT & CLARIFY",
836 + "STANDARDISE & IDENTIFY",
837 + "STANDARDIZE & IDENTIFY",
838 + "OPEN, REUSE & MAKE FINDABLE"
839 + ]
840 + },
841 + {
842 + name:"GREEN",
843 + accent:"#38b76a",
844 + bg:"#edf9f1",
845 + text:"#3f7451",
846 + labels:[
847 + "INFRASTRUKTUR EINRICHTEN",
848 + "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN",
849 + "SPEICHERN & ZUGRIFF STEUERN",
850 + "REPOSITORIUM, ERHALTEN & ÜBERGEBEN",
851 + "SET UP INFRASTRUCTURE",
852 + "SET UP INFRASTRUCTURE & COLLABORATION",
853 + "STORE & CONTROL ACCESS",
854 + "REPOSITORY, PRESERVE & HAND OVER"
855 + ]
691 691   }
857 + ];
692 692  
693 - var r=el.getBoundingClientRect();
694 -
695 - return (
696 - r.width>=(minW||1)&&
697 - r.height>=(minH||1)
698 - );
859 + function num(value){
860 + var n=parseFloat(value);
861 + return Number.isFinite(n)?n:0;
699 699   }
700 700  
701 - function excluded(el){
702 - return (
703 - !el.matches||
704 - el.matches(
705 - "button,input,select,textarea,option,label,img,svg,canvas,table,thead,tbody,tfoot,tr,td,th,summary,script,style,noscript,template,.btn,.chip,[role=button]"
706 - )
707 - );
864 + function norm(value){
865 + return String(value||"")
866 + .replace(/\s+/g," ")
867 + .trim()
868 + .toUpperCase();
708 708   }
709 709  
710 - function namedLikeBox(el){
711 - var c=
712 - typeof el.className==="string"
713 - ? el.className
714 - : "";
871 + function visible(el){
872 + if(!el||el.nodeType!==1)return false;
715 715  
716 - return /(^|[s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([s_-]|$)/i.test(c);
717 - }
874 + var style=getComputedStyle(el);
875 + var rect=el.getBoundingClientRect();
718 718  
719 - function boxLike(el){
720 - if(!visible(el,MIN_W,MIN_H)||excluded(el))return false;
721 -
722 - var s=getComputedStyle(el);
723 - var r=el.getBoundingClientRect();
724 -
725 - var border=
726 - num(s.borderTopWidth)+
727 - num(s.borderRightWidth)+
728 - num(s.borderBottomWidth)+
729 - num(s.borderLeftWidth);
730 -
731 - var radius=Math.max(
732 - num(s.borderTopLeftRadius),
733 - num(s.borderTopRightRadius),
734 - num(s.borderBottomLeftRadius),
735 - num(s.borderBottomRightRadius)
736 - );
737 -
738 - var bg=
739 - s.backgroundColor&&
740 - s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
741 - s.backgroundColor!=="transparent";
742 -
743 - var shadow=
744 - s.boxShadow&&
745 - s.boxShadow!=="none";
746 -
747 747   return (
748 - namedLikeBox(el)||
749 - border>=1||
750 - (bg&&radius>=3)||
751 - (shadow&&r.width>=180)
878 + style.display!=="none"&&
879 + style.visibility!=="hidden"&&
880 + rect.width>20&&
881 + rect.height>4
752 752   );
753 753   }
754 754  
755 - function saveOriginal(el,map,property){
885 + function saveStyle(el,map,property){
756 756   if(map.has(el))return;
757 757  
758 758   map.set(el,{
... ... @@ -761,7 +761,7 @@
761 761   });
762 762   }
763 763  
764 - function restoreOriginal(el,map,property){
894 + function restoreStyle(el,map,property){
765 765   var original=map.get(el);
766 766  
767 767   if(original&&original.value){
... ... @@ -775,247 +775,470 @@
775 775   }
776 776   }
777 777  
778 - function reset(){
779 - heightManaged.forEach(function(el){
780 - restoreOriginal(
908 + function resetRuntime(){
909 + managedHeight.forEach(function(el){
910 + restoreStyle(
781 781   el,
782 - originalMinHeight,
912 + originalHeight,
783 783   "min-height"
784 784   );
785 -
786 786   el.removeAttribute(
787 - "data-sn-equal-height-managed"
916 + "data-sn-master-equal-height"
788 788   );
789 789   });
790 790  
791 - sectionManaged.forEach(function(el){
792 - restoreOriginal(
920 + managedMargin.forEach(function(el){
921 + restoreStyle(
793 793   el,
794 - originalMarginTop,
923 + originalMargin,
795 795   "margin-top"
796 796   );
797 -
798 798   el.removeAttribute(
799 - "data-sn-first-section-aligned"
927 + "data-sn-master-first-row"
800 800   );
801 801   });
802 802  
803 - heightManaged.clear();
804 - sectionManaged.clear();
931 + managedHeight.clear();
932 + managedMargin.clear();
805 805   }
806 806  
807 - function pickTarget(child){
808 - if(!visible(child,MIN_W,MIN_H))return null;
935 + function themeFor(text){
936 + var value=norm(text);
809 809  
810 - if(boxLike(child)){
811 - return child;
938 + for(var i=0;i<THEMES.length;i++){
939 + for(var j=0;j<THEMES[i].labels.length;j++){
940 + var label=THEMES[i].labels[j];
941 +
942 + if(
943 + value===label||
944 + value.indexOf(label+" ")===0||
945 + value.indexOf(label+" -")===0||
946 + value.indexOf(label+" ·")===0
947 + ){
948 + return THEMES[i];
949 + }
950 + }
812 812   }
813 813  
814 - var cr=child.getBoundingClientRect();
815 - var q=[];
953 + return null;
954 + }
816 816  
817 - Array.from(child.children||[]).forEach(function(el){
818 - q.push({el:el,depth:1});
956 + /* =======================================================
957 + BORDERLESS FILLED RED/ORANGE CTA BUTTONS
958 + ======================================================= */
959 +
960 + function colourDistance(a,b){
961 + return Math.sqrt(
962 + Math.pow(a[0]-b[0],2)+
963 + Math.pow(a[1]-b[1],2)+
964 + Math.pow(a[2]-b[2],2)
965 + );
966 + }
967 +
968 + function makeFilledRedOrangeCTAsBorderless(){
969 + var RED_ORANGE=[233,75,19];
970 +
971 + Array.from(
972 + root.querySelectorAll(
973 + 'a,button,[role="button"],input[type="submit"],input[type="button"]'
974 + )
975 + ).forEach(function(el){
976 + if(!visible(el))return;
977 +
978 + var style=getComputedStyle(el);
979 + var rgb=parseRGB(style.backgroundColor);
980 +
981 + if(!rgb)return;
982 +
983 + if(
984 + colourDistance(
985 + rgb,
986 + RED_ORANGE
987 + )>55
988 + ){
989 + return;
990 + }
991 +
992 + var rect=el.getBoundingClientRect();
993 +
994 + if(
995 + rect.width<80||
996 + rect.height<24
997 + ){
998 + return;
999 + }
1000 +
1001 + el.style.setProperty(
1002 + "border",
1003 + "none",
1004 + "important"
1005 + );
1006 +
1007 + el.style.setProperty(
1008 + "border-left",
1009 + "none",
1010 + "important"
1011 + );
1012 +
1013 + el.style.setProperty(
1014 + "border-top",
1015 + "none",
1016 + "important"
1017 + );
1018 +
1019 + el.style.setProperty(
1020 + "border-right",
1021 + "none",
1022 + "important"
1023 + );
1024 +
1025 + el.style.setProperty(
1026 + "border-bottom",
1027 + "none",
1028 + "important"
1029 + );
1030 +
1031 + el.style.setProperty(
1032 + "box-shadow",
1033 + "none",
1034 + "important"
1035 + );
819 819   });
1037 + }
820 820  
821 - var best=null;
822 - var bestScore=-Infinity;
1039 + /* =======================================================
1040 + FULL-WIDTH THREE-LINE AREA LABELS
1041 + ======================================================= */
823 823  
824 - while(q.length){
825 - var item=q.shift();
826 - var el=item.el;
1043 + function compactText(value){
1044 + return String(value||"")
1045 + .replace(/\s+/g," ")
1046 + .trim();
1047 + }
827 827  
828 - if(!visible(el,MIN_W,MIN_H))continue;
1049 + function makeThreeLineAreaLabels(){
1050 + Array.from(
1051 + root.querySelectorAll(
1052 + ".arsn-area-label"
1053 + )
1054 + ).forEach(function(label){
1055 + if(
1056 + label.getAttribute(
1057 + "data-sn-three-line"
1058 + )==="1"
1059 + ){
1060 + return;
1061 + }
829 829  
830 - var r=el.getBoundingClientRect();
1063 + var number=
1064 + label.querySelector(
1065 + ":scope > .arsn-area-number"
1066 + );
831 831  
1068 + var action=
1069 + label.querySelector(
1070 + ":scope > .arsn-area-action"
1071 + );
1072 +
832 832   if(
833 - r.width>=cr.width*.68&&
834 - boxLike(el)
1074 + !number||
1075 + !action
835 835   ){
836 - var widthFit=
837 - 1-Math.min(
838 - 1,
839 - Math.abs(cr.width-r.width)/
840 - Math.max(1,cr.width)
841 - );
1077 + return;
1078 + }
842 842  
843 - var topFit=
844 - 1-Math.min(
845 - 1,
846 - Math.abs(cr.top-r.top)/100
847 - );
1080 + var clone=
1081 + label.cloneNode(true);
848 848  
849 - var score=
850 - widthFit*6+
851 - topFit*3+
852 - Math.min(r.height,900)/450+
853 - Math.min(r.width*r.height,900000)/900000;
1083 + var cloneNumber=
1084 + clone.querySelector(
1085 + ":scope > .arsn-area-number"
1086 + );
854 854  
855 - if(score>bestScore){
856 - best=el;
857 - bestScore=score;
858 - }
1088 + var cloneAction=
1089 + clone.querySelector(
1090 + ":scope > .arsn-area-action"
1091 + );
1092 +
1093 + if(cloneNumber){
1094 + cloneNumber.remove();
859 859   }
860 860  
861 - if(item.depth<SEARCH_DEPTH){
862 - Array.from(el.children||[]).forEach(function(next){
863 - q.push({
864 - el:next,
865 - depth:item.depth+1
866 - });
867 - });
1097 + if(cloneAction){
1098 + cloneAction.remove();
868 868   }
869 - }
870 870  
871 - return best;
872 - }
1101 + var titleText=
1102 + compactText(
1103 + clone.textContent
1104 + );
873 873  
874 - function groupsByVisualRow(entries){
875 - var groups=[];
1106 + if(!titleText){
1107 + return;
1108 + }
876 876  
877 - entries
878 - .slice()
879 - .sort(function(a,b){
880 - return (
881 - a.rect.top-b.rect.top||
882 - a.rect.left-b.rect.left
1110 + var numberNode=
1111 + number.cloneNode(true);
1112 +
1113 + var actionNode=
1114 + action.cloneNode(true);
1115 +
1116 + var titleNode=
1117 + document.createElement(
1118 + "span"
883 883   );
884 - })
885 - .forEach(function(entry){
886 - var group=null;
887 887  
888 - for(var i=0;i<groups.length;i++){
889 - if(
890 - Math.abs(
891 - groups[i].top-
892 - entry.rect.top
893 - )<=ROW_TOLERANCE
894 - ){
895 - group=groups[i];
896 - break;
897 - }
898 - }
1121 + titleNode.className=
1122 + "sn-area-label-title";
899 899  
900 - if(!group){
901 - group={
902 - top:entry.rect.top,
903 - entries:[]
904 - };
905 - groups.push(group);
906 - }
1124 + titleNode.textContent=
1125 + titleText;
907 907  
908 - group.entries.push(entry);
909 - });
1127 + while(label.firstChild){
1128 + label.removeChild(
1129 + label.firstChild
1130 + );
1131 + }
910 910  
911 - return groups;
1133 + label.appendChild(
1134 + numberNode
1135 + );
1136 +
1137 + label.appendChild(
1138 + titleNode
1139 + );
1140 +
1141 + label.appendChild(
1142 + actionNode
1143 + );
1144 +
1145 + label.setAttribute(
1146 + "data-sn-three-line",
1147 + "1"
1148 + );
1149 +
1150 + var head=
1151 + label.closest(
1152 + ".arsn-area-head"
1153 + );
1154 +
1155 + if(head){
1156 + head.style.setProperty(
1157 + "width",
1158 + "100%",
1159 + "important"
1160 + );
1161 +
1162 + head.style.setProperty(
1163 + "max-width",
1164 + "100%",
1165 + "important"
1166 + );
1167 +
1168 + head.style.setProperty(
1169 + "box-sizing",
1170 + "border-box",
1171 + "important"
1172 + );
1173 + }
1174 + });
912 912   }
913 913  
914 - function validHorizontalGroup(group){
915 - if(group.entries.length<2)return false;
1177 + /* =======================================================
1178 + PLACEHOLDER BADGE
1179 + ======================================================= */
916 916  
917 - var lefts=
918 - group.entries
919 - .map(function(e){return e.rect.left;})
920 - .sort(function(a,b){return a-b;});
1181 + function applyPlaceholderBadge(){
1182 + if(!PLACEHOLDER)return;
921 921  
922 922   if(
923 - lefts[lefts.length-1]-
924 - lefts[0]<
925 - 80
1185 + document.querySelector(
1186 + ".sn-coming-soon-badge"
1187 + )
926 926   ){
927 - return false;
1189 + return;
928 928   }
929 929  
930 - var widths=
931 - group.entries
932 - .map(function(e){return e.rect.width;})
933 - .filter(function(w){return w>0;});
1192 + var title=
1193 + document.querySelector(
1194 + "#document-title"
1195 + )||
1196 + document.querySelector(
1197 + "h1"
1198 + );
934 934  
935 - if(widths.length<2)return false;
1200 + if(!title)return;
936 936  
937 - var minWidth=Math.min.apply(Math,widths);
938 - var maxWidth=Math.max.apply(Math,widths);
1202 + var badge=
1203 + document.createElement(
1204 + "span"
1205 + );
939 939  
940 - return (
941 - maxWidth/
942 - Math.max(1,minWidth)<=
943 - 1.9
1207 + badge.className=
1208 + "sn-coming-soon-badge";
1209 +
1210 + badge.textContent=
1211 + PLACEHOLDER_LABEL;
1212 +
1213 + badge.setAttribute(
1214 + "aria-label",
1215 + PLACEHOLDER_LABEL
944 944   );
945 - }
946 946  
947 - function normalizeText(text){
948 - return String(text||"")
949 - .replace(/s+/g," ")
950 - .trim()
951 - .toUpperCase();
1218 + title.appendChild(
1219 + badge
1220 + );
952 952   }
953 953  
954 - function exactKnownFirstSection(el){
955 - var text=normalizeText(el.textContent);
1223 + /* =======================================================
1224 + DETAIL PAGE OWN-ACCENT PROPAGATION
1225 + ======================================================= */
956 956  
957 - return (
958 - text==="HIER STARTEN"||
959 - text==="ORGANISIEREN & DOKUMENTIEREN"||
960 - text==="ENTSCHEIDEN"||
961 - text==="START HERE"||
962 - text==="GET STARTED"||
963 - text==="ORGANISE & DOCUMENT"||
964 - text==="ORGANIZE & DOCUMENT"||
965 - text==="DECIDE"
1227 + function parseRGB(value){
1228 + var match=String(value||"").match(
1229 + /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
966 966   );
1231 +
1232 + if(!match)return null;
1233 +
1234 + return [
1235 + Number(match[1]),
1236 + Number(match[2]),
1237 + Number(match[3])
1238 + ];
967 967   }
968 968  
969 - function visuallyFirstSectionBar(card){
970 - var cardRect=card.getBoundingClientRect();
971 - var candidates=[];
1241 + function distance(a,b){
1242 + return Math.sqrt(
1243 + Math.pow(a[0]-b[0],2)+
1244 + Math.pow(a[1]-b[1],2)+
1245 + Math.pow(a[2]-b[2],2)
1246 + );
1247 + }
972 972  
1249 + function paletteMatch(cssColor){
1250 + var rgb=parseRGB(cssColor);
1251 +
1252 + if(!rgb)return null;
1253 +
1254 + var palette=[
1255 + {hex:"#21b6d7",rgb:[33,182,215]},
1256 + {hex:"#e94b13",rgb:[233,75,19]},
1257 + {hex:"#f0aa00",rgb:[240,170,0]},
1258 + {hex:"#38b76a",rgb:[56,183,106]}
1259 + ];
1260 +
1261 + var best=null;
1262 + var bestDistance=Infinity;
1263 +
1264 + palette.forEach(function(item){
1265 + var d=distance(rgb,item.rgb);
1266 +
1267 + if(d<bestDistance){
1268 + best=item;
1269 + bestDistance=d;
1270 + }
1271 + });
1272 +
1273 + return bestDistance<=30
1274 + ?best
1275 + :null;
1276 + }
1277 +
1278 + function propagateDetailAccents(){
1279 + if(PAGE_KIND!=="detail")return;
1280 +
973 973   Array.from(
974 - card.querySelectorAll(
975 - "div,p,span,strong,h3,h4,h5,h6"
1282 + root.querySelectorAll(
1283 + ".arsn-call,.dmp-call,.ido-call,.pp-call,"+
1284 + ".arsn-source,.dmp-source,.ido-source,.pp-source"
976 976   )
977 977   ).forEach(function(el){
978 - if(!visible(el,20,6))return;
979 - if(excluded(el))return;
1287 + if(!visible(el))return;
980 980  
981 - var r=el.getBoundingClientRect();
982 - var relativeTop=r.top-cardRect.top;
1289 + var style=getComputedStyle(el);
983 983  
984 984   if(
985 - relativeTop<45||
986 - relativeTop>cardRect.height*.72
1292 + num(style.borderTopWidth)>=2
987 987   ){
988 - return;
1294 + var match=
1295 + paletteMatch(
1296 + style.borderTopColor
1297 + );
1298 +
1299 + if(match){
1300 + el.style.setProperty(
1301 + "border-left",
1302 + "4px solid "+match.hex,
1303 + "important"
1304 + );
1305 + }
989 989   }
1307 + });
990 990  
991 - var widthRatio=
992 - r.width/
993 - Math.max(1,cardRect.width);
1309 + // Warning families: explicit safety override.
1310 + Array.from(
1311 + root.querySelectorAll(
1312 + ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+
1313 + ".warn,.warning,.warningmessage,.errormessage"
1314 + )
1315 + ).forEach(function(el){
1316 + if(!visible(el))return;
994 994  
995 - if(
996 - widthRatio<.55||
997 - widthRatio>1.05||
998 - r.height>54
999 - ){
1000 - return;
1001 - }
1318 + el.style.setProperty(
1319 + "border-left",
1320 + "4px solid #e94b13",
1321 + "important"
1322 + );
1323 + });
1002 1002  
1003 - var text=normalizeText(el.textContent);
1325 + // Info families: explicit orientation override.
1326 + Array.from(
1327 + root.querySelectorAll(
1328 + ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage"
1329 + )
1330 + ).forEach(function(el){
1331 + if(!visible(el))return;
1004 1004  
1005 - if(
1006 - text.length<2||
1007 - text.length>90
1008 - ){
1009 - return;
1010 - }
1333 + el.style.setProperty(
1334 + "border-left",
1335 + "4px solid #21b6d7",
1336 + "important"
1337 + );
1338 + });
1339 + }
1011 1011  
1012 - var style=getComputedStyle(el);
1341 + /* =======================================================
1342 + OVERVIEW SEMANTIC THEME PALETTE
1343 + ======================================================= */
1013 1013  
1014 - var bg=
1015 - style.backgroundColor&&
1016 - style.backgroundColor!=="rgba(0, 0, 0, 0)"&&
1017 - style.backgroundColor!=="transparent";
1345 + function smallestThemeHeaders(){
1346 + return Array.from(
1347 + root.querySelectorAll(
1348 + "div,span,p,strong,h3,h4,h5,h6"
1349 + )
1350 + ).filter(function(el){
1351 + if(!visible(el))return false;
1352 + if(!themeFor(el.textContent))return false;
1018 1018  
1354 + return !Array.from(
1355 + el.children||[]
1356 + ).some(function(child){
1357 + return !!themeFor(
1358 + child.textContent
1359 + );
1360 + });
1361 + });
1362 + }
1363 +
1364 + function findOverviewCard(header){
1365 + var node=header.parentElement;
1366 + var candidates=[];
1367 +
1368 + while(node&&node!==root){
1369 + var rect=node.getBoundingClientRect();
1370 + var style=getComputedStyle(node);
1371 +
1019 1019   var border=
1020 1020   num(style.borderTopWidth)+
1021 1021   num(style.borderRightWidth)+
... ... @@ -1022,315 +1022,755 @@
1022 1022   num(style.borderBottomWidth)+
1023 1023   num(style.borderLeftWidth);
1024 1024  
1025 - var mostlyUpper=
1026 - text.length>=3&&
1027 - text===text.toUpperCase();
1028 -
1029 - var exact=exactKnownFirstSection(el);
1030 -
1031 - var score=
1032 - (exact?20:0)+
1033 - (bg?6:0)+
1034 - (border>=1?2:0)+
1035 - (mostlyUpper?4:0)+
1036 - (num(style.fontWeight)>=600?1:0);
1037 -
1038 - if(score>=7){
1039 - candidates.push({
1040 - el:el,
1041 - relativeTop:relativeTop,
1042 - width:r.width,
1043 - score:score
1044 - });
1378 + if(
1379 + rect.width>=220&&
1380 + rect.width<=800&&
1381 + rect.height>=120&&
1382 + border>=1
1383 + ){
1384 + candidates.push(node);
1045 1045   }
1046 - });
1047 1047  
1387 + node=node.parentElement;
1388 + }
1389 +
1048 1048   if(!candidates.length)return null;
1049 1049  
1050 1050   candidates.sort(function(a,b){
1051 - if(a.score!==b.score)return b.score-a.score;
1052 - if(Math.abs(a.relativeTop-b.relativeTop)>3){
1053 - return a.relativeTop-b.relativeTop;
1054 - }
1055 - return b.width-a.width;
1393 + return (
1394 + b.getBoundingClientRect().height-
1395 + a.getBoundingClientRect().height
1396 + );
1056 1056   });
1057 1057  
1058 - // For exact known labels always prefer the earliest exact match.
1059 - var exacts=candidates.filter(function(c){
1060 - return exactKnownFirstSection(c.el);
1061 - });
1399 + return candidates[0];
1400 + }
1062 1062  
1063 - if(exacts.length){
1064 - exacts.sort(function(a,b){
1065 - return a.relativeTop-b.relativeTop||b.width-a.width;
1066 - });
1067 - return exacts[0].el;
1068 - }
1402 + function rowCandidates(link,card){
1403 + var result=[];
1404 + var cardRect=
1405 + card.getBoundingClientRect();
1069 1069  
1070 - // Generic fallback: earliest high-confidence bar.
1071 - candidates.sort(function(a,b){
1072 - return a.relativeTop-b.relativeTop||b.score-a.score||b.width-a.width;
1073 - });
1407 + var node=link;
1074 1074  
1075 - return candidates[0].el;
1076 - }
1409 + while(node&&node!==card){
1410 + if(visible(node)){
1411 + var rect=
1412 + node.getBoundingClientRect();
1077 1077  
1078 - function alignFirstSections(cards){
1079 - var rows=
1080 - cards.map(function(card){
1081 - var bar=
1082 - visuallyFirstSectionBar(card);
1414 + if(
1415 + rect.height<=105&&
1416 + rect.width>=
1417 + cardRect.width*.50&&
1418 + rect.width<=
1419 + cardRect.width*1.03
1420 + ){
1421 + result.push(node);
1422 + }
1423 + }
1083 1083  
1084 - if(!bar)return null;
1425 + node=node.parentElement;
1426 + }
1085 1085  
1086 - var cardRect=
1087 - card.getBoundingClientRect();
1428 + return result;
1429 + }
1088 1088  
1089 - var barRect=
1090 - bar.getBoundingClientRect();
1431 + function chooseOuterRow(
1432 + candidates,
1433 + link
1434 + ){
1435 + if(!candidates.length){
1436 + return link;
1437 + }
1091 1091  
1092 - return {
1093 - card:card,
1094 - bar:bar,
1095 - relativeTop:
1096 - barRect.top-cardRect.top,
1097 - label:
1098 - normalizeText(bar.textContent)
1099 - };
1439 + var bordered=
1440 + candidates.filter(function(el){
1441 + return (
1442 + num(
1443 + getComputedStyle(el)
1444 + .borderLeftWidth
1445 + )>=1
1446 + );
1100 1100   });
1101 1101  
1102 - // Conservative: only align when every card in the horizontal row
1103 - // has a reliable first section bar.
1104 - if(
1105 - rows.some(function(row){
1106 - return !row;
1107 - })
1108 - ){
1109 - return null;
1449 + var pool=
1450 + bordered.length
1451 + ?bordered
1452 + :candidates;
1453 +
1454 + pool.sort(function(a,b){
1455 + var ar=
1456 + a.getBoundingClientRect();
1457 +
1458 + var br=
1459 + b.getBoundingClientRect();
1460 +
1461 + return (
1462 + ar.left-br.left||
1463 + br.width-ar.width
1464 + );
1465 + });
1466 +
1467 + return pool[0]||link;
1468 + }
1469 +
1470 + function applyOverviewPalette(){
1471 + if(PAGE_KIND!=="overview"){
1472 + return [];
1110 1110   }
1111 1111  
1112 - var targetTop=
1113 - Math.max.apply(
1114 - Math,
1115 - rows.map(function(row){
1116 - return row.relativeTop;
1475 + var headers=
1476 + smallestThemeHeaders()
1477 + .map(function(el){
1478 + return {
1479 + el:el,
1480 + theme:
1481 + themeFor(
1482 + el.textContent
1483 + ),
1484 + card:
1485 + findOverviewCard(
1486 + el
1487 + )
1488 + };
1117 1117   })
1118 - );
1490 + .filter(function(row){
1491 + return !!row.card;
1492 + });
1119 1119  
1120 - rows.forEach(function(row){
1121 - var delta=
1122 - targetTop-
1123 - row.relativeTop;
1494 + var unique=[];
1495 + var seenHeaders=new Set();
1124 1124  
1125 - if(delta<=1)return;
1497 + headers.forEach(function(row){
1498 + var key=
1499 + row.theme.name+
1500 + "|"+
1501 + Math.round(
1502 + row.card
1503 + .getBoundingClientRect()
1504 + .left
1505 + )+
1506 + "|"+
1507 + Math.round(
1508 + row.el
1509 + .getBoundingClientRect()
1510 + .top
1511 + );
1126 1126  
1127 - saveOriginal(
1128 - row.bar,
1129 - originalMarginTop,
1130 - "margin-top"
1513 + if(!seenHeaders.has(key)){
1514 + seenHeaders.add(key);
1515 + unique.push(row);
1516 + }
1517 + });
1518 +
1519 + unique.forEach(function(row){
1520 + var headerRect=
1521 + row.el
1522 + .getBoundingClientRect();
1523 +
1524 + row.el.style.setProperty(
1525 + "background",
1526 + row.theme.bg,
1527 + "important"
1131 1131   );
1132 1132  
1133 - var currentMargin=
1134 - num(
1135 - getComputedStyle(
1136 - row.bar
1137 - ).marginTop
1138 - );
1530 + row.el.style.setProperty(
1531 + "color",
1532 + row.theme.text,
1533 + "important"
1534 + );
1139 1139  
1140 - row.bar.style.setProperty(
1141 - "margin-top",
1142 - (
1143 - currentMargin+
1144 - delta
1145 - )+"px"
1536 + row.el.style.setProperty(
1537 + "text-align",
1538 + "left",
1539 + "important"
1146 1146   );
1147 1147  
1148 - row.bar.setAttribute(
1149 - "data-sn-first-section-aligned",
1150 - "4"
1542 + row.el.style.setProperty(
1543 + "word-spacing",
1544 + "normal",
1545 + "important"
1151 1151   );
1152 1152  
1153 - sectionManaged.add(row.bar);
1548 + var later=
1549 + unique
1550 + .filter(function(other){
1551 + return (
1552 + other.card===row.card&&
1553 + other.el
1554 + .getBoundingClientRect()
1555 + .top>
1556 + headerRect.top+2
1557 + );
1558 + })
1559 + .sort(function(a,b){
1560 + return (
1561 + a.el
1562 + .getBoundingClientRect()
1563 + .top-
1564 + b.el
1565 + .getBoundingClientRect()
1566 + .top
1567 + );
1568 + });
1569 +
1570 + var stopTop=
1571 + later.length
1572 + ?later[0].el
1573 + .getBoundingClientRect()
1574 + .top
1575 + :Infinity;
1576 +
1577 + Array.from(
1578 + row.card.querySelectorAll("a")
1579 + ).forEach(function(link){
1580 + if(
1581 + link.classList &&
1582 + link.classList.contains(
1583 + "arsn-phase-cta"
1584 + )
1585 + ){
1586 + return;
1587 + }
1588 +
1589 + if(!visible(link))return;
1590 +
1591 + var rect=
1592 + link.getBoundingClientRect();
1593 +
1594 + if(
1595 + rect.top<=
1596 + headerRect.bottom-2||
1597 + rect.top>=
1598 + stopTop-2
1599 + ){
1600 + return;
1601 + }
1602 +
1603 + var candidates=
1604 + rowCandidates(
1605 + link,
1606 + row.card
1607 + );
1608 +
1609 + var target=
1610 + chooseOuterRow(
1611 + candidates,
1612 + link
1613 + );
1614 +
1615 + candidates.forEach(function(el){
1616 + el.style.setProperty(
1617 + "border-left",
1618 + "0 solid transparent",
1619 + "important"
1620 + );
1621 + });
1622 +
1623 + target.style.setProperty(
1624 + "border-left",
1625 + "3px solid "+
1626 + row.theme.accent,
1627 + "important"
1628 + );
1629 +
1630 + target.style.setProperty(
1631 + "box-sizing",
1632 + "border-box",
1633 + "important"
1634 + );
1635 + });
1154 1154   });
1155 1155  
1156 - return {
1157 - labels:
1158 - rows.map(function(row){
1159 - return row.label;
1160 - }),
1161 - targetRelativeTop:
1162 - Math.round(targetTop)
1163 - };
1638 + return unique;
1164 1164   }
1165 1165  
1166 - function applyGroup(group){
1167 - if(!validHorizontalGroup(group)){
1168 - return null;
1641 + /* =======================================================
1642 + OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1643 + ======================================================= */
1644 +
1645 + function alignOverviewCards(headers){
1646 + if(
1647 + PAGE_KIND!=="overview"||
1648 + window.innerWidth<=MOBILE_MAX
1649 + ){
1650 + return;
1169 1169   }
1170 1170  
1171 1171   var cards=[];
1172 1172   var seen=new Set();
1173 1173  
1174 - group.entries.forEach(function(entry){
1175 - if(!seen.has(entry.target)){
1176 - seen.add(entry.target);
1177 - cards.push(entry.target);
1656 + headers.forEach(function(row){
1657 + if(!seen.has(row.card)){
1658 + seen.add(row.card);
1659 + cards.push(row.card);
1178 1178   }
1179 1179   });
1180 1180  
1181 - if(cards.length<2)return null;
1663 + if(cards.length<2){
1664 + return;
1665 + }
1182 1182  
1183 - var firstSection=
1184 - alignFirstSections(cards);
1667 + // Group cards by actual top position.
1668 + var groups=[];
1185 1185  
1186 - // The section alignment can change natural card heights.
1187 - // Measure only afterwards.
1188 - var maxHeight=0;
1189 -
1190 1190   cards.forEach(function(card){
1191 - maxHeight=Math.max(
1192 - maxHeight,
1193 - card.getBoundingClientRect().height
1194 - );
1671 + var top=
1672 + card.getBoundingClientRect().top;
1673 +
1674 + var group=null;
1675 +
1676 + for(var i=0;i<groups.length;i++){
1677 + if(
1678 + Math.abs(
1679 + groups[i].top-top
1680 + )<=ROW_TOLERANCE
1681 + ){
1682 + group=groups[i];
1683 + break;
1684 + }
1685 + }
1686 +
1687 + if(!group){
1688 + group={
1689 + top:top,
1690 + cards:[]
1691 + };
1692 + groups.push(group);
1693 + }
1694 +
1695 + group.cards.push(card);
1195 1195   });
1196 1196  
1197 - maxHeight=Math.ceil(maxHeight);
1698 + groups.forEach(function(group){
1699 + if(group.cards.length<2){
1700 + return;
1701 + }
1198 1198  
1199 - if(maxHeight<MIN_H)return null;
1703 + var firstHeaders=
1704 + group.cards.map(function(card){
1705 + var candidates=
1706 + headers
1707 + .filter(function(row){
1708 + return row.card===card;
1709 + })
1710 + .sort(function(a,b){
1711 + return (
1712 + a.el
1713 + .getBoundingClientRect()
1714 + .top-
1715 + b.el
1716 + .getBoundingClientRect()
1717 + .top
1718 + );
1719 + });
1200 1200  
1201 - cards.forEach(function(card){
1202 - saveOriginal(
1203 - card,
1204 - originalMinHeight,
1205 - "min-height"
1206 - );
1721 + return candidates.length
1722 + ?candidates[0]
1723 + :null;
1724 + });
1207 1207  
1208 - card.style.setProperty(
1209 - "min-height",
1210 - maxHeight+"px"
1211 - );
1726 + if(
1727 + !firstHeaders.some(function(row){
1728 + return !row;
1729 + })
1730 + ){
1731 + var targetTop=
1732 + Math.max.apply(
1733 + Math,
1734 + firstHeaders.map(function(row){
1735 + return (
1736 + row.el
1737 + .getBoundingClientRect()
1738 + .top-
1739 + row.card
1740 + .getBoundingClientRect()
1741 + .top
1742 + );
1743 + })
1744 + );
1212 1212  
1213 - card.setAttribute(
1214 - "data-sn-equal-height-managed",
1215 - "4"
1216 - );
1746 + firstHeaders.forEach(function(row){
1747 + var relativeTop=
1748 + row.el
1749 + .getBoundingClientRect()
1750 + .top-
1751 + row.card
1752 + .getBoundingClientRect()
1753 + .top;
1217 1217  
1218 - heightManaged.add(card);
1219 - });
1755 + var delta=
1756 + targetTop-relativeTop;
1220 1220  
1221 - return {
1222 - cards:cards.length,
1223 - height:maxHeight,
1224 - firstSection:firstSection
1225 - };
1758 + if(delta>1){
1759 + saveStyle(
1760 + row.el,
1761 + originalMargin,
1762 + "margin-top"
1763 + );
1764 +
1765 + var current=
1766 + num(
1767 + getComputedStyle(
1768 + row.el
1769 + ).marginTop
1770 + );
1771 +
1772 + row.el.style.setProperty(
1773 + "margin-top",
1774 + (
1775 + current+delta
1776 + )+"px"
1777 + );
1778 +
1779 + row.el.setAttribute(
1780 + "data-sn-master-first-row",
1781 + "1"
1782 + );
1783 +
1784 + managedMargin.add(
1785 + row.el
1786 + );
1787 + }
1788 + });
1789 + }
1790 +
1791 + var maxHeight=0;
1792 +
1793 + group.cards.forEach(function(card){
1794 + maxHeight=
1795 + Math.max(
1796 + maxHeight,
1797 + card
1798 + .getBoundingClientRect()
1799 + .height
1800 + );
1801 + });
1802 +
1803 + maxHeight=
1804 + Math.ceil(maxHeight);
1805 +
1806 + group.cards.forEach(function(card){
1807 + saveStyle(
1808 + card,
1809 + originalHeight,
1810 + "min-height"
1811 + );
1812 +
1813 + card.style.setProperty(
1814 + "min-height",
1815 + maxHeight+"px"
1816 + );
1817 +
1818 + card.setAttribute(
1819 + "data-sn-master-equal-height",
1820 + "1"
1821 + );
1822 +
1823 + managedHeight.add(
1824 + card
1825 + );
1826 + });
1827 + });
1226 1226   }
1227 1227  
1228 - function run(){
1229 - reset();
1830 + /* =======================================================
1831 + DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY
1832 + ======================================================= */
1230 1230  
1834 + function equaliseDetailGrids(){
1231 1231   if(
1836 + PAGE_KIND!=="detail"||
1232 1232   window.innerWidth<=MOBILE_MAX
1233 1233   ){
1234 1234   return;
1235 1235   }
1236 1236  
1237 - var parents=
1842 + var selectors=[
1843 + ".arsn-grid",
1844 + ".arsn-grid-2",
1845 + ".arsn-grid-3",
1846 + ".dmp-grid",
1847 + ".ido-grid",
1848 + ".pp-grid"
1849 + ];
1850 +
1851 + selectors.forEach(function(selector){
1238 1238   Array.from(
1239 - root.querySelectorAll("*")
1240 - ).filter(function(parent){
1241 - return (
1242 - visible(parent,MIN_W,MIN_H)&&
1243 - parent.children&&
1244 - parent.children.length>=2&&
1245 - parent.children.length<=MAX_PARENT_CHILDREN
1246 - );
1247 - });
1853 + root.querySelectorAll(selector)
1854 + ).forEach(function(grid){
1855 + var children=
1856 + Array.from(
1857 + grid.children||[]
1858 + ).filter(visible);
1248 1248  
1249 - var touched=new Set();
1860 + if(children.length<2){
1861 + return;
1862 + }
1250 1250  
1251 - parents.forEach(function(parent){
1252 - var entries=[];
1864 + var groups=[];
1253 1253  
1254 - Array.from(parent.children).forEach(function(child){
1255 - if(!visible(child,MIN_W,MIN_H))return;
1866 + children.forEach(function(child){
1867 + var top=
1868 + child
1869 + .getBoundingClientRect()
1870 + .top;
1256 1256  
1257 - var target=pickTarget(child);
1258 - if(!target)return;
1872 + var group=null;
1259 1259  
1260 - entries.push({
1261 - target:target,
1262 - rect:target.getBoundingClientRect()
1874 + for(var i=0;i<groups.length;i++){
1875 + if(
1876 + Math.abs(
1877 + groups[i].top-top
1878 + )<=ROW_TOLERANCE
1879 + ){
1880 + group=groups[i];
1881 + break;
1882 + }
1883 + }
1884 +
1885 + if(!group){
1886 + group={
1887 + top:top,
1888 + items:[]
1889 + };
1890 + groups.push(group);
1891 + }
1892 +
1893 + group.items.push(child);
1263 1263   });
1264 - });
1265 1265  
1266 - if(entries.length<2)return;
1896 + groups.forEach(function(group){
1897 + if(group.items.length<2){
1898 + return;
1899 + }
1267 1267  
1268 - groupsByVisualRow(entries).forEach(function(group){
1269 - if(!validHorizontalGroup(group))return;
1901 + var maxHeight=0;
1270 1270  
1271 - var signature=
1272 - group.entries.map(function(entry){
1273 - return entry.target;
1903 + group.items.forEach(function(item){
1904 + maxHeight=
1905 + Math.max(
1906 + maxHeight,
1907 + item
1908 + .getBoundingClientRect()
1909 + .height
1910 + );
1274 1274   });
1275 1275  
1276 - if(
1277 - !signature.some(function(el){
1278 - return !touched.has(el);
1279 - })
1280 - ){
1281 - return;
1282 - }
1913 + maxHeight=
1914 + Math.ceil(maxHeight);
1283 1283  
1284 - var applied=
1285 - applyGroup(group);
1916 + group.items.forEach(function(item){
1917 + saveStyle(
1918 + item,
1919 + originalHeight,
1920 + "min-height"
1921 + );
1286 1286  
1287 - if(applied){
1288 - signature.forEach(function(el){
1289 - touched.add(el);
1923 + item.style.setProperty(
1924 + "min-height",
1925 + maxHeight+"px"
1926 + );
1927 +
1928 + item.setAttribute(
1929 + "data-sn-master-equal-height",
1930 + "1"
1931 + );
1932 +
1933 + managedHeight.add(item);
1290 1290   });
1291 - }
1935 + });
1292 1292   });
1293 1293   });
1294 1294   }
1295 1295  
1296 - function schedule(){
1297 - if(raf)cancelAnimationFrame(raf);
1940 + /* =======================================================
1941 + RUN / RESPONSIVE SCHEDULING
1942 + ======================================================= */
1298 1298  
1299 - raf=requestAnimationFrame(function(){
1300 - raf=requestAnimationFrame(function(){
1301 - raf=0;
1302 - run();
1303 - });
1304 - });
1944 + function run(){
1945 + if(running)return;
1946 +
1947 + running=true;
1948 +
1949 + try{
1950 + resetRuntime();
1951 + applyPlaceholderBadge();
1952 + propagateDetailAccents();
1953 +
1954 + var headers=
1955 + applyOverviewPalette();
1956 +
1957 + makeThreeLineAreaLabels();
1958 + makeFilledRedOrangeCTAsBorderless();
1959 +
1960 + if(
1961 + window.innerWidth>
1962 + MOBILE_MAX
1963 + ){
1964 + alignOverviewCards(
1965 + headers
1966 + );
1967 +
1968 + equaliseDetailGrids();
1969 + }
1970 + }finally{
1971 + running=false;
1972 + }
1305 1305   }
1306 1306  
1307 - addEventListener("resize",schedule,{passive:true});
1308 - addEventListener("load",schedule,{once:true});
1975 + function onResize(){
1976 + if(resizeTimer){
1977 + clearTimeout(
1978 + resizeTimer
1979 + );
1980 + }
1309 1309  
1310 - root.addEventListener(
1311 - "click",
1312 - function(){
1313 - setTimeout(schedule,0);
1314 - },
1315 - true
1316 - );
1982 + resizeTimer=
1983 + setTimeout(
1984 + function(){
1985 + resizeTimer=0;
1986 + run();
1987 + },
1988 + RESIZE_DEBOUNCE
1989 + );
1990 + }
1317 1317  
1318 - Array.from(root.querySelectorAll("img")).forEach(function(img){
1319 - if(!img.complete){
1320 - img.addEventListener("load",schedule,{once:true});
1992 + async function waitForReady(){
1993 + if(
1994 + document.readyState!=="complete"
1995 + ){
1996 + await new Promise(function(resolve){
1997 + window.addEventListener(
1998 + "load",
1999 + resolve,
2000 + {once:true}
2001 + );
2002 + });
1321 1321   }
1322 - });
1323 1323  
1324 - if(document.fonts&&document.fonts.ready){
1325 - document.fonts.ready.then(schedule);
2005 + if(
2006 + document.fonts&&
2007 + document.fonts.ready
2008 + ){
2009 + try{
2010 + await document.fonts.ready;
2011 + }catch(error){}
2012 + }
2013 +
2014 + var images=
2015 + Array.from(
2016 + root.querySelectorAll("img")
2017 + );
2018 +
2019 + await Promise.all(
2020 + images.map(function(img){
2021 + if(img.complete){
2022 + return Promise.resolve();
2023 + }
2024 +
2025 + return new Promise(function(resolve){
2026 + var done=function(){
2027 + resolve();
2028 + };
2029 +
2030 + img.addEventListener(
2031 + "load",
2032 + done,
2033 + {once:true}
2034 + );
2035 +
2036 + img.addEventListener(
2037 + "error",
2038 + done,
2039 + {once:true}
2040 + );
2041 + });
2042 + })
2043 + );
2044 +
2045 + run();
1326 1326   }
1327 1327  
1328 - schedule();
1329 - setTimeout(schedule,200);
1330 - setTimeout(schedule,650);
1331 - setTimeout(schedule,1400);
2048 + window.addEventListener(
2049 + "resize",
2050 + onResize,
2051 + {passive:true}
2052 + );
2053 +
2054 + waitForReady();
1332 1332  })();
1333 1333  </script>
1334 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
2057 +
2058 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
1335 1335  {{/html}}
1336 1336  
2061 +{{html clean="false"}}
2062 +<!-- ARSN_PHASE_CTA_MOBILE_EDGE_FIX_V3_START -->
2063 +<style data-arsn-phase-cta-mobile-edge-fix="3">
2064 +@media (max-width:767px){
2065 +
2066 + /* Remove the white side gutters around the three phase CTAs. */
2067 + #xwikicontent .arsn-phase-cta-wrap{
2068 + box-sizing:border-box!important;
2069 + width:calc(100% + 2px)!important;
2070 + max-width:none!important;
2071 + margin:14px -1px -1px -1px!important;
2072 + padding:0!important;
2073 + border:0!important;
2074 + border-left:0!important;
2075 + box-shadow:none!important;
2076 + background:transparent!important;
2077 + }
2078 +
2079 + /* Full-width orange CTA; no extra border/shadow. */
2080 + #xwikicontent a.arsn-phase-cta{
2081 + display:flex!important;
2082 + align-items:center!important;
2083 + justify-content:center!important;
2084 + gap:8px!important;
2085 +
2086 + box-sizing:border-box!important;
2087 + width:100%!important;
2088 + max-width:none!important;
2089 + min-width:0!important;
2090 +
2091 + margin:0!important;
2092 + padding:12px 14px!important;
2093 +
2094 + border:0!important;
2095 + border-left:0!important;
2096 + border-right:0!important;
2097 + border-top:0!important;
2098 + border-bottom:0!important;
2099 + box-shadow:none!important;
2100 +
2101 + border-radius:8px!important;
2102 +
2103 + text-align:center!important;
2104 + text-align-last:center!important;
2105 + text-justify:auto!important;
2106 + word-spacing:normal!important;
2107 + white-space:normal!important;
2108 + }
2109 +
2110 + /* Keep an XWiki external-link icon on the same line/flex row. */
2111 + #xwikicontent a.arsn-phase-cta::after{
2112 + flex:0 0 auto!important;
2113 + margin-left:2px!important;
2114 + }
2115 +
2116 + #xwikicontent a.arsn-phase-cta > .fa,
2117 + #xwikicontent a.arsn-phase-cta > .icon,
2118 + #xwikicontent a.arsn-phase-cta > .external-link-icon,
2119 + #xwikicontent a.arsn-phase-cta > [class*="external"]{
2120 + position:static!important;
2121 + display:inline-block!important;
2122 + flex:0 0 auto!important;
2123 + margin:0!important;
2124 + }
2125 +}
2126 +</style>
2127 +<!-- ARSN_PHASE_CTA_MOBILE_EDGE_FIX_V3_END -->
2128 +{{/html}}
2129 +