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

From version 39.23
edited by Veronika Kocher
on Thursday, 03 Sep 2026 10:09
Change comment: There is no comment for this version
To version 41.3
edited by Veronika Kocher
on Friday, 04 Sep 2026 14:23
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -2,18 +2,14 @@
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 +
8 + **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.
10 + 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;" %)
438 +(% 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"]]
440 +[[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;" %)
504 +(% 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"]]
506 +[[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;" %)
580 +(% 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"]]
582 +[[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,11 @@
592 592  
593 593  (% style="margin-top:30px;" %)
594 594  (((
591 +
592 +<!-- ARSN_TRAINING_WORKSHOPS_INCLUDE_V1_START -->
593 +{{include reference="Service Navigator.Art & Research Services Navigator.Code.TrainingWorkshopsBlock" author="target" /}}
594 +<!-- ARSN_TRAINING_WORKSHOPS_INCLUDE_V1_END -->
595 +
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.
... ... @@ -639,12 +639,13 @@
639 639  {{/info}}
640 640  )))
641 641  
642 -\n\n
643 -\n\n{{html clean="false"}}
644 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
643 +{{html clean="false"}}
644 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
645 645  
646 -<style data-sn-horizontal-box-harmonizer="7">
647 -/* ---------- Typography: never justify headings ---------- */
646 +<style data-sn-service-navigator-master="1">
647 +/* =========================================================
648 + MASTER TYPOGRAPHY
649 + ========================================================= */
648 648  #xwikicontent h1,
649 649  #xwikicontent h2,
650 650  #xwikicontent h3,
... ... @@ -666,88 +666,105 @@
666 666   word-spacing:normal!important;
667 667  }
668 668  
669 -/* ---------- Native XWiki semantic callouts ---------- */
670 -#xwikicontent .box.infomessage,
671 -#xwikicontent .infomessage,
672 -#xwikicontent .box.warningmessage,
673 -#xwikicontent .warningmessage,
674 -#xwikicontent .box.successmessage,
675 -#xwikicontent .successmessage,
676 -#xwikicontent .box.errormessage,
677 -#xwikicontent .errormessage,
678 -#xwikicontent [data-sn-callout-harmonized="1"]{
671 +/* =========================================================
672 + COMING SOON / IN VORBEREITUNG
673 + ========================================================= */
674 +.sn-coming-soon-badge{
675 + display:inline-block;
676 + vertical-align:middle;
677 + margin-left:10px;
678 + padding:4px 8px;
679 + border-radius:14px;
680 + border:1px solid #efd9cc;
681 + background:#fff4ee;
682 + color:#8a4d36;
683 + font-size:11px;
684 + font-weight:700;
685 + letter-spacing:.055em;
686 + line-height:1.2;
687 + white-space:nowrap;
688 +}
689 +
690 +/* =========================================================
691 + NATIVE / DETAIL CALLOUT GEOMETRY
692 + Preserve existing backgrounds.
693 + ========================================================= */
694 +#xwikicontent .arsn-info,
695 +#xwikicontent .dmp-info,
696 +#xwikicontent .ido-info,
697 +#xwikicontent .pp-info,
698 +#xwikicontent .infomessage{
679 679   box-sizing:border-box!important;
680 - border-radius:8px!important;
681 - border-top:1px solid rgba(0,0,0,.08)!important;
682 - border-right:1px solid rgba(0,0,0,.08)!important;
683 - border-bottom:1px solid rgba(0,0,0,.08)!important;
684 - border-left:4px solid var(--sn-callout-accent,#21b6d7)!important;
685 - padding:14px 16px!important;
700 + border-left:4px solid #21b6d7!important;
701 + border-radius:8px;
686 686   text-align:left!important;
687 - text-justify:auto!important;
688 688   word-spacing:normal!important;
689 - box-shadow:none!important;
690 690  }
691 691  
692 -#xwikicontent .box.infomessage,
693 -#xwikicontent .infomessage{
694 - --sn-callout-accent:#21b6d7;
695 - background:#eaf7fb!important;
696 -}
697 -
698 -#xwikicontent .box.warningmessage,
699 -#xwikicontent .warningmessage{
700 - --sn-callout-accent:#f0aa00;
701 - background:#fff8e7!important;
702 -}
703 -
704 -#xwikicontent .box.successmessage,
705 -#xwikicontent .successmessage{
706 - --sn-callout-accent:#38b76a;
707 - background:#edf9f1!important;
708 -}
709 -
710 -#xwikicontent .box.errormessage,
706 +#xwikicontent .arsn-warn,
707 +#xwikicontent .dmp-warn,
708 +#xwikicontent .ido-warn,
709 +#xwikicontent .pp-warn,
710 +#xwikicontent .warn,
711 +#xwikicontent .warning,
712 +#xwikicontent .warningmessage,
711 711  #xwikicontent .errormessage{
712 - --sn-callout-accent:#e94b13;
713 - background:#fff1ec!important;
714 + box-sizing:border-box!important;
715 + border-left:4px solid #e94b13!important;
716 + border-radius:8px;
717 + text-align:left!important;
718 + word-spacing:normal!important;
714 714  }
715 715  
716 -#xwikicontent [data-sn-callout-harmonized="1"] > :first-child,
717 -#xwikicontent .infomessage > :first-child,
718 -#xwikicontent .warningmessage > :first-child,
719 -#xwikicontent .successmessage > :first-child,
720 -#xwikicontent .errormessage > :first-child{
721 - margin-top:0!important;
721 +[data-sn-master-equal-height],
722 +[data-sn-master-first-row]{
723 + box-sizing:border-box;
722 722  }
723 723  
724 -#xwikicontent [data-sn-callout-harmonized="1"] > :last-child,
725 -#xwikicontent .infomessage > :last-child,
726 -#xwikicontent .warningmessage > :last-child,
727 -#xwikicontent .successmessage > :last-child,
728 -#xwikicontent .errormessage > :last-child{
729 - margin-bottom:0!important;
726 +/* =========================================================
727 + FULL-WIDTH THREE-LINE NUMBER / TITLE / SUBTITLE BLOCKS
728 + ========================================================= */
729 +#xwikicontent .arsn-area-label[data-sn-three-line="1"]{
730 + display:grid!important;
731 + grid-template-columns:minmax(0,1fr)!important;
732 + grid-auto-rows:auto!important;
733 + width:100%!important;
734 + max-width:none!important;
735 + box-sizing:border-box!important;
736 + justify-items:start!important;
737 + align-items:start!important;
738 + gap:2px!important;
739 + text-align:left!important;
740 + text-align-last:left!important;
741 + text-justify:auto!important;
742 + word-spacing:normal!important;
743 + white-space:normal!important;
730 730  }
731 -
732 -#xwikicontent [data-sn-equal-height-managed],
733 -#xwikicontent [data-sn-first-section-aligned],
734 -#xwikicontent [data-sn-first-content-aligned]{
735 - box-sizing:border-box;
745 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-number,
746 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .sn-area-label-title,
747 +#xwikicontent .arsn-area-label[data-sn-three-line="1"] > .arsn-area-action{
748 + display:block!important;
749 + width:100%!important;
750 + margin:0!important;
751 + text-align:left!important;
752 + text-align-last:left!important;
753 + text-justify:auto!important;
754 + word-spacing:normal!important;
755 + white-space:normal!important;
736 736  }
737 737  </style>
738 738  
739 -<script data-sn-horizontal-box-harmonizer="7">
759 +<script data-sn-service-navigator-master="1">
740 740  (function(){
741 741   "use strict";
742 742  
763 + var PAGE_KIND="overview";
764 + var PLACEHOLDER=false;
765 + var PLACEHOLDER_LABEL="COMING SOON";
766 +
743 743   var MOBILE_MAX=767;
744 744   var ROW_TOLERANCE=6;
745 - var MIN_W=150;
746 - var MIN_H=36;
747 - var MAX_PARENT_CHILDREN=18;
748 - var SEARCH_DEPTH=5;
749 749   var RESIZE_DEBOUNCE=220;
750 - var MIN_WIDTH_CHANGE=2;
751 751  
752 752   var root=
753 753   document.getElementById("xwikicontent")||
... ... @@ -757,142 +757,114 @@
757 757  
758 758   if(!root)return;
759 759  
760 - var heightManaged=new Set();
761 - var sectionManaged=new Set();
762 - var contentManaged=new Set();
779 + var managedHeight=new Set();
780 + var managedMargin=new Set();
781 + var originalHeight=new WeakMap();
782 + var originalMargin=new WeakMap();
763 763  
764 - var originalMinHeight=new WeakMap();
765 - var originalMarginTop=new WeakMap();
766 -
767 767   var resizeTimer=0;
768 - var lastWidth=-1;
769 - var hasApplied=false;
770 - var applying=false;
785 + var running=false;
771 771  
772 - function num(v){
773 - var n=parseFloat(v);
774 - return Number.isFinite(n)?n:0;
775 - }
776 -
777 - function visible(el,minW,minH){
778 - if(!el||el.nodeType!==1)return false;
779 -
780 - var s=getComputedStyle(el);
781 -
782 - if(
783 - s.display==="none"||
784 - s.visibility==="hidden"||
785 - Number(s.opacity)===0
786 - ){
787 - return false;
787 + var THEMES=[
788 + {
789 + name:"BLUE",
790 + accent:"#21b6d7",
791 + bg:"#eaf7fb",
792 + text:"#315d68",
793 + labels:[
794 + "HIER STARTEN",
795 + "ENTSCHEIDEN",
796 + "ÜBERPRÜFEN & ANPASSEN",
797 + "START HERE",
798 + "DECIDE",
799 + "REVIEW & ADAPT"
800 + ]
801 + },
802 + {
803 + name:"RED",
804 + accent:"#e94b13",
805 + bg:"#fff1ec",
806 + text:"#8a4d36",
807 + labels:[
808 + "PLANEN & ORGANISIEREN",
809 + "ORGANISIEREN & DOKUMENTIEREN",
810 + "PUBLIZIEREN & PRÄSENTIEREN",
811 + "PLAN & ORGANISE",
812 + "PLAN & ORGANIZE",
813 + "ORGANISE & DOCUMENT",
814 + "ORGANIZE & DOCUMENT",
815 + "PUBLISH & PRESENT"
816 + ]
817 + },
818 + {
819 + name:"YELLOW",
820 + accent:"#f0aa00",
821 + bg:"#fff8e7",
822 + text:"#785b17",
823 + labels:[
824 + "SCHÜTZEN & KLÄREN",
825 + "STANDARDISIEREN & IDENTIFIZIEREN",
826 + "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN",
827 + "PROTECT & CLARIFY",
828 + "STANDARDISE & IDENTIFY",
829 + "STANDARDIZE & IDENTIFY",
830 + "OPEN, REUSE & MAKE FINDABLE"
831 + ]
832 + },
833 + {
834 + name:"GREEN",
835 + accent:"#38b76a",
836 + bg:"#edf9f1",
837 + text:"#3f7451",
838 + labels:[
839 + "INFRASTRUKTUR EINRICHTEN",
840 + "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN",
841 + "SPEICHERN & ZUGRIFF STEUERN",
842 + "REPOSITORIUM, ERHALTEN & ÜBERGEBEN",
843 + "SET UP INFRASTRUCTURE",
844 + "SET UP INFRASTRUCTURE & COLLABORATION",
845 + "STORE & CONTROL ACCESS",
846 + "REPOSITORY, PRESERVE & HAND OVER"
847 + ]
788 788   }
849 + ];
789 789  
790 - var r=el.getBoundingClientRect();
791 -
792 - return (
793 - r.width>=(minW||1)&&
794 - r.height>=(minH||1)
795 - );
851 + function num(value){
852 + var n=parseFloat(value);
853 + return Number.isFinite(n)?n:0;
796 796   }
797 797  
798 - function normalizeText(text){
799 - return String(text||"")
856 + function norm(value){
857 + return String(value||"")
800 800   .replace(/\s+/g," ")
801 801   .trim()
802 802   .toUpperCase();
803 803   }
804 804  
805 - function excluded(el){
806 - return (
807 - !el.matches||
808 - el.matches(
809 - "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]"
810 - )
811 - );
812 - }
863 + function visible(el){
864 + if(!el||el.nodeType!==1)return false;
813 813  
814 - /* ---------- Custom coloured callouts ---------- */
866 + var style=getComputedStyle(el);
867 + var rect=el.getBoundingClientRect();
815 815  
816 - function nativeCallout(el){
817 - var c=
818 - typeof el.className==="string"
819 - ? el.className.toLowerCase()
820 - : "";
821 -
822 822   return (
823 - /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c)
870 + style.display!=="none"&&
871 + style.visibility!=="hidden"&&
872 + rect.width>20&&
873 + rect.height>4
824 824   );
825 825   }
826 826  
827 - function customCallout(el){
828 - if(!visible(el,220,42)||excluded(el))return false;
829 -
830 - var r=el.getBoundingClientRect();
831 -
832 - if(r.height>520)return false;
833 -
834 - var s=getComputedStyle(el);
835 -
836 - var bg=
837 - s.backgroundColor&&
838 - s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
839 - s.backgroundColor!=="transparent"&&
840 - s.backgroundColor!=="rgb(255, 255, 255)";
841 -
842 - var left=
843 - num(s.borderLeftWidth);
844 -
845 - return (
846 - bg&&
847 - left>=2
848 - );
849 - }
850 -
851 - function harmoniseCustomCallouts(){
852 - Array.from(
853 - root.querySelectorAll(
854 - "div,aside,section"
855 - )
856 - ).forEach(function(el){
857 - if(nativeCallout(el))return;
858 - if(!customCallout(el))return;
859 -
860 - var s=getComputedStyle(el);
861 -
862 - el.setAttribute(
863 - "data-sn-callout-harmonized",
864 - "1"
865 - );
866 -
867 - if(
868 - s.borderLeftColor
869 - ){
870 - el.style.setProperty(
871 - "--sn-callout-accent",
872 - s.borderLeftColor
873 - );
874 - }
875 - });
876 - }
877 -
878 - /* ---------- Restore only values V7 itself changed ---------- */
879 -
880 - function saveOriginal(el,map,property){
877 + function saveStyle(el,map,property){
881 881   if(map.has(el))return;
882 882  
883 883   map.set(el,{
884 - value:
885 - el.style.getPropertyValue(
886 - property
887 - ),
888 - priority:
889 - el.style.getPropertyPriority(
890 - property
891 - )
881 + value:el.style.getPropertyValue(property),
882 + priority:el.style.getPropertyPriority(property)
892 892   });
893 893   }
894 894  
895 - function restoreOriginal(el,map,property){
886 + function restoreStyle(el,map,property){
896 896   var original=map.get(el);
897 897  
898 898   if(original&&original.value){
... ... @@ -902,770 +902,1078 @@
902 902   original.priority||""
903 903   );
904 904   }else{
905 - el.style.removeProperty(
906 - property
907 - );
896 + el.style.removeProperty(property);
908 908   }
909 909   }
910 910  
911 911   function resetRuntime(){
912 - heightManaged.forEach(function(el){
913 - restoreOriginal(
901 + managedHeight.forEach(function(el){
902 + restoreStyle(
914 914   el,
915 - originalMinHeight,
904 + originalHeight,
916 916   "min-height"
917 917   );
918 -
919 919   el.removeAttribute(
920 - "data-sn-equal-height-managed"
908 + "data-sn-master-equal-height"
921 921   );
922 922   });
923 923  
924 - sectionManaged.forEach(function(el){
925 - restoreOriginal(
912 + managedMargin.forEach(function(el){
913 + restoreStyle(
926 926   el,
927 - originalMarginTop,
915 + originalMargin,
928 928   "margin-top"
929 929   );
930 -
931 931   el.removeAttribute(
932 - "data-sn-first-section-aligned"
919 + "data-sn-master-first-row"
933 933   );
934 934   });
935 935  
936 - contentManaged.forEach(function(el){
937 - restoreOriginal(
938 - el,
939 - originalMarginTop,
940 - "margin-top"
941 - );
923 + managedHeight.clear();
924 + managedMargin.clear();
925 + }
942 942  
943 - el.removeAttribute(
944 - "data-sn-first-content-aligned"
945 - );
946 - });
927 + function themeFor(text){
928 + var value=norm(text);
947 947  
948 - heightManaged.clear();
949 - sectionManaged.clear();
950 - contentManaged.clear();
951 - }
930 + for(var i=0;i<THEMES.length;i++){
931 + for(var j=0;j<THEMES[i].labels.length;j++){
932 + var label=THEMES[i].labels[j];
952 952  
953 - /* ---------- Card detection ---------- */
934 + if(
935 + value===label||
936 + value.indexOf(label+" ")===0||
937 + value.indexOf(label+" -")===0||
938 + value.indexOf(label+" ·")===0
939 + ){
940 + return THEMES[i];
941 + }
942 + }
943 + }
954 954  
955 - function namedLikeBox(el){
956 - var c=
957 - typeof el.className==="string"
958 - ? el.className
959 - : "";
945 + return null;
946 + }
960 960  
961 - return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c);
948 + /* =======================================================
949 + BORDERLESS FILLED RED/ORANGE CTA BUTTONS
950 + ======================================================= */
951 +
952 + function colourDistance(a,b){
953 + return Math.sqrt(
954 + Math.pow(a[0]-b[0],2)+
955 + Math.pow(a[1]-b[1],2)+
956 + Math.pow(a[2]-b[2],2)
957 + );
962 962   }
963 963  
964 - function boxLike(el){
965 - if(
966 - !visible(el,MIN_W,MIN_H)||
967 - excluded(el)
968 - ){
969 - return false;
970 - }
960 + function makeFilledRedOrangeCTAsBorderless(){
961 + var RED_ORANGE=[233,75,19];
971 971  
972 - var s=getComputedStyle(el);
973 - var r=el.getBoundingClientRect();
963 + Array.from(
964 + root.querySelectorAll(
965 + 'a,button,[role="button"],input[type="submit"],input[type="button"]'
966 + )
967 + ).forEach(function(el){
968 + if(!visible(el))return;
974 974  
975 - var border=
976 - num(s.borderTopWidth)+
977 - num(s.borderRightWidth)+
978 - num(s.borderBottomWidth)+
979 - num(s.borderLeftWidth);
970 + var style=getComputedStyle(el);
971 + var rgb=parseRGB(style.backgroundColor);
980 980  
981 - var radius=Math.max(
982 - num(s.borderTopLeftRadius),
983 - num(s.borderTopRightRadius),
984 - num(s.borderBottomLeftRadius),
985 - num(s.borderBottomRightRadius)
986 - );
973 + if(!rgb)return;
987 987  
988 - var bg=
989 - s.backgroundColor&&
990 - s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
991 - s.backgroundColor!=="transparent";
975 + if(
976 + colourDistance(
977 + rgb,
978 + RED_ORANGE
979 + )>55
980 + ){
981 + return;
982 + }
992 992  
993 - var shadow=
994 - s.boxShadow&&
995 - s.boxShadow!=="none";
984 + var rect=el.getBoundingClientRect();
996 996  
997 - return (
998 - namedLikeBox(el)||
999 - border>=1||
1000 - (bg&&radius>=3)||
1001 - (shadow&&r.width>=180)
1002 - );
1003 - }
986 + if(
987 + rect.width<80||
988 + rect.height<24
989 + ){
990 + return;
991 + }
1004 1004  
1005 - function pickTarget(child){
1006 - if(!visible(child,MIN_W,MIN_H))return null;
993 + el.style.setProperty(
994 + "border",
995 + "none",
996 + "important"
997 + );
1007 1007  
1008 - if(boxLike(child))return child;
999 + el.style.setProperty(
1000 + "border-left",
1001 + "none",
1002 + "important"
1003 + );
1009 1009  
1010 - var cr=child.getBoundingClientRect();
1011 - var q=[];
1005 + el.style.setProperty(
1006 + "border-top",
1007 + "none",
1008 + "important"
1009 + );
1012 1012  
1013 - Array.from(child.children||[]).forEach(function(el){
1014 - q.push({el:el,depth:1});
1011 + el.style.setProperty(
1012 + "border-right",
1013 + "none",
1014 + "important"
1015 + );
1016 +
1017 + el.style.setProperty(
1018 + "border-bottom",
1019 + "none",
1020 + "important"
1021 + );
1022 +
1023 + el.style.setProperty(
1024 + "box-shadow",
1025 + "none",
1026 + "important"
1027 + );
1015 1015   });
1029 + }
1016 1016  
1017 - var best=null;
1018 - var bestScore=-Infinity;
1031 + /* =======================================================
1032 + FULL-WIDTH THREE-LINE AREA LABELS
1033 + ======================================================= */
1019 1019  
1020 - while(q.length){
1021 - var item=q.shift();
1022 - var el=item.el;
1035 + function compactText(value){
1036 + return String(value||"")
1037 + .replace(/\s+/g," ")
1038 + .trim();
1039 + }
1023 1023  
1024 - if(!visible(el,MIN_W,MIN_H))continue;
1041 + function makeThreeLineAreaLabels(){
1042 + Array.from(
1043 + root.querySelectorAll(
1044 + ".arsn-area-label"
1045 + )
1046 + ).forEach(function(label){
1047 + if(
1048 + label.getAttribute(
1049 + "data-sn-three-line"
1050 + )==="1"
1051 + ){
1052 + return;
1053 + }
1025 1025  
1026 - var r=el.getBoundingClientRect();
1055 + var number=
1056 + label.querySelector(
1057 + ":scope > .arsn-area-number"
1058 + );
1027 1027  
1060 + var action=
1061 + label.querySelector(
1062 + ":scope > .arsn-area-action"
1063 + );
1064 +
1028 1028   if(
1029 - r.width>=cr.width*.68&&
1030 - boxLike(el)
1066 + !number||
1067 + !action
1031 1031   ){
1032 - var widthFit=
1033 - 1-Math.min(
1034 - 1,
1035 - Math.abs(cr.width-r.width)/
1036 - Math.max(1,cr.width)
1037 - );
1069 + return;
1070 + }
1038 1038  
1039 - var topFit=
1040 - 1-Math.min(
1041 - 1,
1042 - Math.abs(cr.top-r.top)/100
1043 - );
1072 + var clone=
1073 + label.cloneNode(true);
1044 1044  
1045 - var score=
1046 - widthFit*6+
1047 - topFit*3+
1048 - Math.min(r.height,900)/450+
1049 - Math.min(r.width*r.height,900000)/900000;
1075 + var cloneNumber=
1076 + clone.querySelector(
1077 + ":scope > .arsn-area-number"
1078 + );
1050 1050  
1051 - if(score>bestScore){
1052 - best=el;
1053 - bestScore=score;
1054 - }
1080 + var cloneAction=
1081 + clone.querySelector(
1082 + ":scope > .arsn-area-action"
1083 + );
1084 +
1085 + if(cloneNumber){
1086 + cloneNumber.remove();
1055 1055   }
1056 1056  
1057 - if(item.depth<SEARCH_DEPTH){
1058 - Array.from(el.children||[]).forEach(function(next){
1059 - q.push({
1060 - el:next,
1061 - depth:item.depth+1
1062 - });
1063 - });
1089 + if(cloneAction){
1090 + cloneAction.remove();
1064 1064   }
1065 - }
1066 1066  
1067 - return best;
1068 - }
1093 + var titleText=
1094 + compactText(
1095 + clone.textContent
1096 + );
1069 1069  
1070 - function groupRows(entries){
1071 - var groups=[];
1098 + if(!titleText){
1099 + return;
1100 + }
1072 1072  
1073 - entries
1074 - .slice()
1075 - .sort(function(a,b){
1076 - return (
1077 - a.rect.top-b.rect.top||
1078 - a.rect.left-b.rect.left
1102 + var numberNode=
1103 + number.cloneNode(true);
1104 +
1105 + var actionNode=
1106 + action.cloneNode(true);
1107 +
1108 + var titleNode=
1109 + document.createElement(
1110 + "span"
1079 1079   );
1080 - })
1081 - .forEach(function(entry){
1082 - var group=null;
1083 1083  
1084 - for(var i=0;i<groups.length;i++){
1085 - if(
1086 - Math.abs(
1087 - groups[i].top-
1088 - entry.rect.top
1089 - )<=ROW_TOLERANCE
1090 - ){
1091 - group=groups[i];
1092 - break;
1093 - }
1094 - }
1113 + titleNode.className=
1114 + "sn-area-label-title";
1095 1095  
1096 - if(!group){
1097 - group={
1098 - top:entry.rect.top,
1099 - entries:[]
1100 - };
1101 - groups.push(group);
1102 - }
1116 + titleNode.textContent=
1117 + titleText;
1103 1103  
1104 - group.entries.push(entry);
1105 - });
1119 + while(label.firstChild){
1120 + label.removeChild(
1121 + label.firstChild
1122 + );
1123 + }
1106 1106  
1107 - return groups;
1125 + label.appendChild(
1126 + numberNode
1127 + );
1128 +
1129 + label.appendChild(
1130 + titleNode
1131 + );
1132 +
1133 + label.appendChild(
1134 + actionNode
1135 + );
1136 +
1137 + label.setAttribute(
1138 + "data-sn-three-line",
1139 + "1"
1140 + );
1141 +
1142 + var head=
1143 + label.closest(
1144 + ".arsn-area-head"
1145 + );
1146 +
1147 + if(head){
1148 + head.style.setProperty(
1149 + "width",
1150 + "100%",
1151 + "important"
1152 + );
1153 +
1154 + head.style.setProperty(
1155 + "max-width",
1156 + "100%",
1157 + "important"
1158 + );
1159 +
1160 + head.style.setProperty(
1161 + "box-sizing",
1162 + "border-box",
1163 + "important"
1164 + );
1165 + }
1166 + });
1108 1108   }
1109 1109  
1110 - function validRow(group){
1111 - if(group.entries.length<2)return false;
1169 + /* =======================================================
1170 + PLACEHOLDER BADGE
1171 + ======================================================= */
1112 1112  
1113 - var lefts=
1114 - group.entries
1115 - .map(function(e){return e.rect.left;})
1116 - .sort(function(a,b){return a-b;});
1173 + function applyPlaceholderBadge(){
1174 + if(!PLACEHOLDER)return;
1117 1117  
1118 1118   if(
1119 - lefts[lefts.length-1]-
1120 - lefts[0]<
1121 - 80
1177 + document.querySelector(
1178 + ".sn-coming-soon-badge"
1179 + )
1122 1122   ){
1123 - return false;
1181 + return;
1124 1124   }
1125 1125  
1126 - var widths=
1127 - group.entries
1128 - .map(function(e){return e.rect.width;})
1129 - .filter(function(w){return w>0;});
1184 + var title=
1185 + document.querySelector(
1186 + "#document-title"
1187 + )||
1188 + document.querySelector(
1189 + "h1"
1190 + );
1130 1130  
1131 - if(widths.length<2)return false;
1192 + if(!title)return;
1132 1132  
1133 - var minW=
1134 - Math.min.apply(Math,widths);
1194 + var badge=
1195 + document.createElement(
1196 + "span"
1197 + );
1135 1135  
1136 - var maxW=
1137 - Math.max.apply(Math,widths);
1199 + badge.className=
1200 + "sn-coming-soon-badge";
1138 1138  
1139 - return (
1140 - maxW/
1141 - Math.max(1,minW)<=
1142 - 1.9
1202 + badge.textContent=
1203 + PLACEHOLDER_LABEL;
1204 +
1205 + badge.setAttribute(
1206 + "aria-label",
1207 + PLACEHOLDER_LABEL
1143 1143   );
1209 +
1210 + title.appendChild(
1211 + badge
1212 + );
1144 1144   }
1145 1145  
1146 - /* ---------- Known ARSN first section bars ---------- */
1215 + /* =======================================================
1216 + DETAIL PAGE OWN-ACCENT PROPAGATION
1217 + ======================================================= */
1147 1147  
1148 - function knownBar(el){
1149 - var text=
1150 - normalizeText(
1151 - el.textContent
1152 - );
1219 + function parseRGB(value){
1220 + var match=String(value||"").match(
1221 + /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
1222 + );
1153 1153  
1154 - return (
1155 - text==="HIER STARTEN"||
1156 - text==="ORGANISIEREN & DOKUMENTIEREN"||
1157 - text==="ENTSCHEIDEN"||
1158 - text==="START HERE"||
1159 - text==="GET STARTED"||
1160 - text==="ORGANISE & DOCUMENT"||
1161 - text==="ORGANIZE & DOCUMENT"||
1162 - text==="DECIDE"
1224 + if(!match)return null;
1225 +
1226 + return [
1227 + Number(match[1]),
1228 + Number(match[2]),
1229 + Number(match[3])
1230 + ];
1231 + }
1232 +
1233 + function distance(a,b){
1234 + return Math.sqrt(
1235 + Math.pow(a[0]-b[0],2)+
1236 + Math.pow(a[1]-b[1],2)+
1237 + Math.pow(a[2]-b[2],2)
1163 1163   );
1164 1164   }
1165 1165  
1166 - function findKnownBar(card){
1167 - var cardRect=
1168 - card.getBoundingClientRect();
1241 + function paletteMatch(cssColor){
1242 + var rgb=parseRGB(cssColor);
1169 1169  
1170 - var rows=
1171 - Array.from(
1172 - card.querySelectorAll(
1173 - "div,p,span,strong,h3,h4,h5,h6"
1174 - )
1175 - )
1176 - .filter(function(el){
1177 - if(!visible(el,20,6))return false;
1178 - if(!knownBar(el))return false;
1244 + if(!rgb)return null;
1179 1179  
1180 - var r=el.getBoundingClientRect();
1246 + var palette=[
1247 + {hex:"#21b6d7",rgb:[33,182,215]},
1248 + {hex:"#e94b13",rgb:[233,75,19]},
1249 + {hex:"#f0aa00",rgb:[240,170,0]},
1250 + {hex:"#38b76a",rgb:[56,183,106]}
1251 + ];
1181 1181  
1182 - var rel=
1183 - r.top-
1184 - cardRect.top;
1253 + var best=null;
1254 + var bestDistance=Infinity;
1185 1185  
1186 - return (
1187 - rel>=35&&
1188 - rel<=
1189 - cardRect.height*.75
1190 - );
1191 - })
1192 - .sort(function(a,b){
1193 - return (
1194 - a.getBoundingClientRect().top-
1195 - b.getBoundingClientRect().top
1196 - );
1197 - });
1256 + palette.forEach(function(item){
1257 + var d=distance(rgb,item.rgb);
1198 1198  
1199 - return rows[0]||null;
1259 + if(d<bestDistance){
1260 + best=item;
1261 + bestDistance=d;
1262 + }
1263 + });
1264 +
1265 + return bestDistance<=30
1266 + ?best
1267 + :null;
1200 1200   }
1201 1201  
1202 - function alignKnownBars(cards){
1203 - var rows=
1204 - cards.map(function(card){
1205 - var bar=
1206 - findKnownBar(card);
1270 + function propagateDetailAccents(){
1271 + if(PAGE_KIND!=="detail")return;
1207 1207  
1208 - if(!bar)return null;
1273 + Array.from(
1274 + root.querySelectorAll(
1275 + ".arsn-call,.dmp-call,.ido-call,.pp-call,"+
1276 + ".arsn-source,.dmp-source,.ido-source,.pp-source"
1277 + )
1278 + ).forEach(function(el){
1279 + if(!visible(el))return;
1209 1209  
1210 - var cr=
1211 - card.getBoundingClientRect();
1281 + var style=getComputedStyle(el);
1212 1212  
1213 - var br=
1214 - bar.getBoundingClientRect();
1283 + if(
1284 + num(style.borderTopWidth)>=2
1285 + ){
1286 + var match=
1287 + paletteMatch(
1288 + style.borderTopColor
1289 + );
1215 1215  
1216 - return {
1217 - bar:bar,
1218 - relativeTop:
1219 - br.top-
1220 - cr.top
1221 - };
1222 - });
1291 + if(match){
1292 + el.style.setProperty(
1293 + "border-left",
1294 + "4px solid "+match.hex,
1295 + "important"
1296 + );
1297 + }
1298 + }
1299 + });
1223 1223  
1224 - if(
1225 - rows.some(function(row){
1226 - return !row;
1227 - })
1228 - ){
1229 - return false;
1230 - }
1301 + // Warning families: explicit safety override.
1302 + Array.from(
1303 + root.querySelectorAll(
1304 + ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+
1305 + ".warn,.warning,.warningmessage,.errormessage"
1306 + )
1307 + ).forEach(function(el){
1308 + if(!visible(el))return;
1231 1231  
1232 - var target=
1233 - Math.max.apply(
1234 - Math,
1235 - rows.map(function(row){
1236 - return row.relativeTop;
1237 - })
1310 + el.style.setProperty(
1311 + "border-left",
1312 + "4px solid #e94b13",
1313 + "important"
1238 1238   );
1315 + });
1239 1239  
1240 - rows.forEach(function(row){
1241 - var delta=
1242 - target-
1243 - row.relativeTop;
1317 + // Info families: explicit orientation override.
1318 + Array.from(
1319 + root.querySelectorAll(
1320 + ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage"
1321 + )
1322 + ).forEach(function(el){
1323 + if(!visible(el))return;
1244 1244  
1245 - if(delta<=1)return;
1246 -
1247 - saveOriginal(
1248 - row.bar,
1249 - originalMarginTop,
1250 - "margin-top"
1325 + el.style.setProperty(
1326 + "border-left",
1327 + "4px solid #21b6d7",
1328 + "important"
1251 1251   );
1330 + });
1331 + }
1252 1252  
1253 - var current=
1254 - num(
1255 - getComputedStyle(
1256 - row.bar
1257 - ).marginTop
1333 + /* =======================================================
1334 + OVERVIEW SEMANTIC THEME PALETTE
1335 + ======================================================= */
1336 +
1337 + function smallestThemeHeaders(){
1338 + return Array.from(
1339 + root.querySelectorAll(
1340 + "div,span,p,strong,h3,h4,h5,h6"
1341 + )
1342 + ).filter(function(el){
1343 + if(!visible(el))return false;
1344 + if(!themeFor(el.textContent))return false;
1345 +
1346 + return !Array.from(
1347 + el.children||[]
1348 + ).some(function(child){
1349 + return !!themeFor(
1350 + child.textContent
1258 1258   );
1352 + });
1353 + });
1354 + }
1259 1259  
1260 - row.bar.style.setProperty(
1261 - "margin-top",
1262 - (
1263 - current+
1264 - delta
1265 - )+"px"
1266 - );
1356 + function findOverviewCard(header){
1357 + var node=header.parentElement;
1358 + var candidates=[];
1267 1267  
1268 - row.bar.setAttribute(
1269 - "data-sn-first-section-aligned",
1270 - "7"
1271 - );
1360 + while(node&&node!==root){
1361 + var rect=node.getBoundingClientRect();
1362 + var style=getComputedStyle(node);
1272 1272  
1273 - sectionManaged.add(
1274 - row.bar
1364 + var border=
1365 + num(style.borderTopWidth)+
1366 + num(style.borderRightWidth)+
1367 + num(style.borderBottomWidth)+
1368 + num(style.borderLeftWidth);
1369 +
1370 + if(
1371 + rect.width>=220&&
1372 + rect.width<=800&&
1373 + rect.height>=120&&
1374 + border>=1
1375 + ){
1376 + candidates.push(node);
1377 + }
1378 +
1379 + node=node.parentElement;
1380 + }
1381 +
1382 + if(!candidates.length)return null;
1383 +
1384 + candidates.sort(function(a,b){
1385 + return (
1386 + b.getBoundingClientRect().height-
1387 + a.getBoundingClientRect().height
1275 1275   );
1276 1276   });
1277 1277  
1278 - return true;
1391 + return candidates[0];
1279 1279   }
1280 1280  
1281 - /* ---------- Generic first content after heading ---------- */
1282 -
1283 - function heading(card){
1284 - var cr=
1394 + function rowCandidates(link,card){
1395 + var result=[];
1396 + var cardRect=
1285 1285   card.getBoundingClientRect();
1286 1286  
1287 - var rows=
1288 - Array.from(
1289 - card.querySelectorAll(
1290 - "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]"
1291 - )
1292 - )
1293 - .filter(function(el){
1294 - if(!visible(el,20,8))return false;
1399 + var node=link;
1295 1295  
1296 - var r=el.getBoundingClientRect();
1401 + while(node&&node!==card){
1402 + if(visible(node)){
1403 + var rect=
1404 + node.getBoundingClientRect();
1297 1297  
1298 - var rel=
1299 - r.top-
1300 - cr.top;
1406 + if(
1407 + rect.height<=105&&
1408 + rect.width>=
1409 + cardRect.width*.50&&
1410 + rect.width<=
1411 + cardRect.width*1.03
1412 + ){
1413 + result.push(node);
1414 + }
1415 + }
1301 1301  
1417 + node=node.parentElement;
1418 + }
1419 +
1420 + return result;
1421 + }
1422 +
1423 + function chooseOuterRow(
1424 + candidates,
1425 + link
1426 + ){
1427 + if(!candidates.length){
1428 + return link;
1429 + }
1430 +
1431 + var bordered=
1432 + candidates.filter(function(el){
1302 1302   return (
1303 - rel>=0&&
1304 - rel<=
1305 - Math.min(
1306 - 160,
1307 - cr.height*.45
1308 - )
1434 + num(
1435 + getComputedStyle(el)
1436 + .borderLeftWidth
1437 + )>=1
1309 1309   );
1310 - })
1311 - .sort(function(a,b){
1312 - return (
1313 - a.getBoundingClientRect().top-
1314 - b.getBoundingClientRect().top
1315 - );
1316 1316   });
1317 1317  
1318 - return rows[0]||null;
1441 + var pool=
1442 + bordered.length
1443 + ?bordered
1444 + :candidates;
1445 +
1446 + pool.sort(function(a,b){
1447 + var ar=
1448 + a.getBoundingClientRect();
1449 +
1450 + var br=
1451 + b.getBoundingClientRect();
1452 +
1453 + return (
1454 + ar.left-br.left||
1455 + br.width-ar.width
1456 + );
1457 + });
1458 +
1459 + return pool[0]||link;
1319 1319   }
1320 1320  
1321 - function firstContent(card,h){
1322 - if(!h)return null;
1462 + function applyOverviewPalette(){
1463 + if(PAGE_KIND!=="overview"){
1464 + return [];
1465 + }
1323 1323  
1324 - var cr=
1325 - card.getBoundingClientRect();
1467 + var headers=
1468 + smallestThemeHeaders()
1469 + .map(function(el){
1470 + return {
1471 + el:el,
1472 + theme:
1473 + themeFor(
1474 + el.textContent
1475 + ),
1476 + card:
1477 + findOverviewCard(
1478 + el
1479 + )
1480 + };
1481 + })
1482 + .filter(function(row){
1483 + return !!row.card;
1484 + });
1326 1326  
1327 - var hr=
1328 - h.getBoundingClientRect();
1486 + var unique=[];
1487 + var seenHeaders=new Set();
1329 1329  
1330 - var rows=
1331 - Array.from(
1332 - card.querySelectorAll(
1333 - "p,div,ul,ol,dl,blockquote"
1334 - )
1335 - )
1336 - .filter(function(el){
1337 - if(
1338 - el===h||
1339 - h.contains(el)||
1340 - el.contains(h)
1341 - ){
1342 - return false;
1343 - }
1489 + headers.forEach(function(row){
1490 + var key=
1491 + row.theme.name+
1492 + "|"+
1493 + Math.round(
1494 + row.card
1495 + .getBoundingClientRect()
1496 + .left
1497 + )+
1498 + "|"+
1499 + Math.round(
1500 + row.el
1501 + .getBoundingClientRect()
1502 + .top
1503 + );
1344 1344  
1345 - if(!visible(el,30,8))return false;
1505 + if(!seenHeaders.has(key)){
1506 + seenHeaders.add(key);
1507 + unique.push(row);
1508 + }
1509 + });
1346 1346  
1347 - var text=
1348 - String(el.textContent||"")
1349 - .replace(/\s+/g," ")
1350 - .trim();
1511 + unique.forEach(function(row){
1512 + var headerRect=
1513 + row.el
1514 + .getBoundingClientRect();
1351 1351  
1352 - if(text.length<3)return false;
1516 + row.el.style.setProperty(
1517 + "background",
1518 + row.theme.bg,
1519 + "important"
1520 + );
1353 1353  
1354 - var r=el.getBoundingClientRect();
1522 + row.el.style.setProperty(
1523 + "color",
1524 + row.theme.text,
1525 + "important"
1526 + );
1355 1355  
1356 - if(
1357 - r.top<
1358 - hr.bottom-1
1359 - ){
1360 - return false;
1361 - }
1528 + row.el.style.setProperty(
1529 + "text-align",
1530 + "left",
1531 + "important"
1532 + );
1362 1362  
1534 + row.el.style.setProperty(
1535 + "word-spacing",
1536 + "normal",
1537 + "important"
1538 + );
1539 +
1540 + var later=
1541 + unique
1542 + .filter(function(other){
1543 + return (
1544 + other.card===row.card&&
1545 + other.el
1546 + .getBoundingClientRect()
1547 + .top>
1548 + headerRect.top+2
1549 + );
1550 + })
1551 + .sort(function(a,b){
1552 + return (
1553 + a.el
1554 + .getBoundingClientRect()
1555 + .top-
1556 + b.el
1557 + .getBoundingClientRect()
1558 + .top
1559 + );
1560 + });
1561 +
1562 + var stopTop=
1563 + later.length
1564 + ?later[0].el
1565 + .getBoundingClientRect()
1566 + .top
1567 + :Infinity;
1568 +
1569 + Array.from(
1570 + row.card.querySelectorAll("a")
1571 + ).forEach(function(link){
1363 1363   if(
1364 - r.top-cr.top>
1365 - Math.min(
1366 - 280,
1367 - cr.height*.65
1573 + link.classList &&
1574 + link.classList.contains(
1575 + "arsn-phase-cta"
1368 1368   )
1369 1369   ){
1370 - return false;
1578 + return;
1371 1371   }
1372 1372  
1581 + if(!visible(link))return;
1582 +
1583 + var rect=
1584 + link.getBoundingClientRect();
1585 +
1373 1373   if(
1374 - r.height>
1375 - cr.height*.58
1587 + rect.top<=
1588 + headerRect.bottom-2||
1589 + rect.top>=
1590 + stopTop-2
1376 1376   ){
1377 - return false;
1592 + return;
1378 1378   }
1379 1379  
1380 - return true;
1381 - })
1382 - .sort(function(a,b){
1383 - var ar=
1384 - a.getBoundingClientRect();
1595 + var candidates=
1596 + rowCandidates(
1597 + link,
1598 + row.card
1599 + );
1385 1385  
1386 - var br=
1387 - b.getBoundingClientRect();
1601 + var target=
1602 + chooseOuterRow(
1603 + candidates,
1604 + link
1605 + );
1388 1388  
1389 - return (
1390 - ar.top-br.top||
1391 - ar.height-br.height
1607 + candidates.forEach(function(el){
1608 + el.style.setProperty(
1609 + "border-left",
1610 + "0 solid transparent",
1611 + "important"
1612 + );
1613 + });
1614 +
1615 + target.style.setProperty(
1616 + "border-left",
1617 + "3px solid "+
1618 + row.theme.accent,
1619 + "important"
1392 1392   );
1621 +
1622 + target.style.setProperty(
1623 + "box-sizing",
1624 + "border-box",
1625 + "important"
1626 + );
1393 1393   });
1628 + });
1394 1394  
1395 - return rows[0]||null;
1630 + return unique;
1396 1396   }
1397 1397  
1398 - function alignGeneric(cards){
1399 - var rows=
1400 - cards.map(function(card){
1401 - var h=
1402 - heading(card);
1633 + /* =======================================================
1634 + OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1635 + ======================================================= */
1403 1403  
1404 - var c=
1405 - firstContent(
1406 - card,
1407 - h
1408 - );
1409 -
1410 - if(!h||!c)return null;
1411 -
1412 - var cr=
1413 - card.getBoundingClientRect();
1414 -
1415 - var rr=
1416 - c.getBoundingClientRect();
1417 -
1418 - return {
1419 - content:c,
1420 - relativeTop:
1421 - rr.top-cr.top
1422 - };
1423 - });
1424 -
1637 + function alignOverviewCards(headers){
1425 1425   if(
1426 - rows.some(function(row){
1427 - return !row;
1428 - })
1639 + PAGE_KIND!=="overview"||
1640 + window.innerWidth<=MOBILE_MAX
1429 1429   ){
1430 - return false;
1642 + return;
1431 1431   }
1432 1432  
1433 - var target=
1434 - Math.max.apply(
1435 - Math,
1436 - rows.map(function(row){
1437 - return row.relativeTop;
1438 - })
1439 - );
1645 + var cards=[];
1646 + var seen=new Set();
1440 1440  
1441 - rows.forEach(function(row){
1442 - var delta=
1443 - target-
1444 - row.relativeTop;
1648 + headers.forEach(function(row){
1649 + if(!seen.has(row.card)){
1650 + seen.add(row.card);
1651 + cards.push(row.card);
1652 + }
1653 + });
1445 1445  
1446 - if(delta<=1)return;
1655 + if(cards.length<2){
1656 + return;
1657 + }
1447 1447  
1448 - saveOriginal(
1449 - row.content,
1450 - originalMarginTop,
1451 - "margin-top"
1452 - );
1659 + // Group cards by actual top position.
1660 + var groups=[];
1453 1453  
1454 - var current=
1455 - num(
1456 - getComputedStyle(
1457 - row.content
1458 - ).marginTop
1459 - );
1662 + cards.forEach(function(card){
1663 + var top=
1664 + card.getBoundingClientRect().top;
1460 1460  
1461 - row.content.style.setProperty(
1462 - "margin-top",
1463 - (
1464 - current+
1465 - delta
1466 - )+"px"
1467 - );
1666 + var group=null;
1468 1468  
1469 - row.content.setAttribute(
1470 - "data-sn-first-content-aligned",
1471 - "7"
1472 - );
1668 + for(var i=0;i<groups.length;i++){
1669 + if(
1670 + Math.abs(
1671 + groups[i].top-top
1672 + )<=ROW_TOLERANCE
1673 + ){
1674 + group=groups[i];
1675 + break;
1676 + }
1677 + }
1473 1473  
1474 - contentManaged.add(
1475 - row.content
1476 - );
1679 + if(!group){
1680 + group={
1681 + top:top,
1682 + cards:[]
1683 + };
1684 + groups.push(group);
1685 + }
1686 +
1687 + group.cards.push(card);
1477 1477   });
1478 1478  
1479 - return true;
1480 - }
1690 + groups.forEach(function(group){
1691 + if(group.cards.length<2){
1692 + return;
1693 + }
1481 1481  
1482 - function applyRow(group){
1483 - if(!validRow(group))return false;
1695 + var firstHeaders=
1696 + group.cards.map(function(card){
1697 + var candidates=
1698 + headers
1699 + .filter(function(row){
1700 + return row.card===card;
1701 + })
1702 + .sort(function(a,b){
1703 + return (
1704 + a.el
1705 + .getBoundingClientRect()
1706 + .top-
1707 + b.el
1708 + .getBoundingClientRect()
1709 + .top
1710 + );
1711 + });
1484 1484  
1485 - var cards=[];
1486 - var seen=new Set();
1713 + return candidates.length
1714 + ?candidates[0]
1715 + :null;
1716 + });
1487 1487  
1488 - group.entries.forEach(function(entry){
1489 - if(!seen.has(entry.target)){
1490 - seen.add(entry.target);
1491 - cards.push(entry.target);
1492 - }
1493 - });
1718 + if(
1719 + !firstHeaders.some(function(row){
1720 + return !row;
1721 + })
1722 + ){
1723 + var targetTop=
1724 + Math.max.apply(
1725 + Math,
1726 + firstHeaders.map(function(row){
1727 + return (
1728 + row.el
1729 + .getBoundingClientRect()
1730 + .top-
1731 + row.card
1732 + .getBoundingClientRect()
1733 + .top
1734 + );
1735 + })
1736 + );
1494 1494  
1495 - if(cards.length<2)return false;
1738 + firstHeaders.forEach(function(row){
1739 + var relativeTop=
1740 + row.el
1741 + .getBoundingClientRect()
1742 + .top-
1743 + row.card
1744 + .getBoundingClientRect()
1745 + .top;
1496 1496  
1497 - if(
1498 - !alignKnownBars(cards)
1499 - ){
1500 - alignGeneric(cards);
1501 - }
1747 + var delta=
1748 + targetTop-relativeTop;
1502 1502  
1503 - var maxHeight=0;
1750 + if(delta>1){
1751 + saveStyle(
1752 + row.el,
1753 + originalMargin,
1754 + "margin-top"
1755 + );
1504 1504  
1505 - cards.forEach(function(card){
1506 - maxHeight=
1507 - Math.max(
1508 - maxHeight,
1509 - card.getBoundingClientRect().height
1510 - );
1511 - });
1757 + var current=
1758 + num(
1759 + getComputedStyle(
1760 + row.el
1761 + ).marginTop
1762 + );
1512 1512  
1513 - maxHeight=
1514 - Math.ceil(
1515 - maxHeight
1516 - );
1764 + row.el.style.setProperty(
1765 + "margin-top",
1766 + (
1767 + current+delta
1768 + )+"px"
1769 + );
1517 1517  
1518 - if(maxHeight<MIN_H)return false;
1771 + row.el.setAttribute(
1772 + "data-sn-master-first-row",
1773 + "1"
1774 + );
1519 1519  
1520 - cards.forEach(function(card){
1521 - saveOriginal(
1522 - card,
1523 - originalMinHeight,
1524 - "min-height"
1525 - );
1776 + managedMargin.add(
1777 + row.el
1778 + );
1779 + }
1780 + });
1781 + }
1526 1526  
1527 - card.style.setProperty(
1528 - "min-height",
1529 - maxHeight+"px"
1530 - );
1783 + var maxHeight=0;
1531 1531  
1532 - card.setAttribute(
1533 - "data-sn-equal-height-managed",
1534 - "7"
1535 - );
1785 + group.cards.forEach(function(card){
1786 + maxHeight=
1787 + Math.max(
1788 + maxHeight,
1789 + card
1790 + .getBoundingClientRect()
1791 + .height
1792 + );
1793 + });
1536 1536  
1537 - heightManaged.add(card);
1538 - });
1795 + maxHeight=
1796 + Math.ceil(maxHeight);
1539 1539  
1540 - return true;
1541 - }
1798 + group.cards.forEach(function(card){
1799 + saveStyle(
1800 + card,
1801 + originalHeight,
1802 + "min-height"
1803 + );
1542 1542  
1543 - function calculate(force){
1544 - if(applying)return;
1805 + card.style.setProperty(
1806 + "min-height",
1807 + maxHeight+"px"
1808 + );
1545 1545  
1546 - var width=
1547 - Math.round(
1548 - window.innerWidth
1549 - );
1810 + card.setAttribute(
1811 + "data-sn-master-equal-height",
1812 + "1"
1813 + );
1550 1550  
1551 - var meaningful=
1552 - lastWidth<0||
1553 - Math.abs(
1554 - width-
1555 - lastWidth
1556 - )>=
1557 - MIN_WIDTH_CHANGE;
1815 + managedHeight.add(
1816 + card
1817 + );
1818 + });
1819 + });
1820 + }
1558 1558  
1822 + /* =======================================================
1823 + DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY
1824 + ======================================================= */
1825 +
1826 + function equaliseDetailGrids(){
1559 1559   if(
1560 - hasApplied&&
1561 - !force&&
1562 - !meaningful
1828 + PAGE_KIND!=="detail"||
1829 + window.innerWidth<=MOBILE_MAX
1563 1563   ){
1564 1564   return;
1565 1565   }
1566 1566  
1567 - applying=true;
1834 + var selectors=[
1835 + ".arsn-grid",
1836 + ".arsn-grid-2",
1837 + ".arsn-grid-3",
1838 + ".dmp-grid",
1839 + ".ido-grid",
1840 + ".pp-grid"
1841 + ];
1568 1568  
1569 - try{
1570 - harmoniseCustomCallouts();
1843 + selectors.forEach(function(selector){
1844 + Array.from(
1845 + root.querySelectorAll(selector)
1846 + ).forEach(function(grid){
1847 + var children=
1848 + Array.from(
1849 + grid.children||[]
1850 + ).filter(visible);
1571 1571  
1572 - if(width<=MOBILE_MAX){
1573 - if(hasApplied){
1574 - resetRuntime();
1852 + if(children.length<2){
1853 + return;
1575 1575   }
1576 1576  
1577 - hasApplied=false;
1578 - lastWidth=width;
1579 - return;
1580 - }
1856 + var groups=[];
1581 1581  
1582 - if(hasApplied){
1583 - resetRuntime();
1584 - }
1858 + children.forEach(function(child){
1859 + var top=
1860 + child
1861 + .getBoundingClientRect()
1862 + .top;
1585 1585  
1586 - var parents=
1587 - Array.from(
1588 - root.querySelectorAll("*")
1589 - )
1590 - .filter(function(parent){
1591 - return (
1592 - visible(
1593 - parent,
1594 - MIN_W,
1595 - MIN_H
1596 - )&&
1597 - parent.children&&
1598 - parent.children.length>=2&&
1599 - parent.children.length<=
1600 - MAX_PARENT_CHILDREN
1601 - );
1602 - });
1864 + var group=null;
1603 1603  
1604 - var touched=
1605 - new Set();
1866 + for(var i=0;i<groups.length;i++){
1867 + if(
1868 + Math.abs(
1869 + groups[i].top-top
1870 + )<=ROW_TOLERANCE
1871 + ){
1872 + group=groups[i];
1873 + break;
1874 + }
1875 + }
1606 1606  
1607 - parents.forEach(function(parent){
1608 - var entries=[];
1877 + if(!group){
1878 + group={
1879 + top:top,
1880 + items:[]
1881 + };
1882 + groups.push(group);
1883 + }
1609 1609  
1610 - Array.from(
1611 - parent.children
1612 - ).forEach(function(child){
1613 - if(
1614 - !visible(
1615 - child,
1616 - MIN_W,
1617 - MIN_H
1618 - )
1619 - ){
1885 + group.items.push(child);
1886 + });
1887 +
1888 + groups.forEach(function(group){
1889 + if(group.items.length<2){
1620 1620   return;
1621 1621   }
1622 1622  
1623 - var target=
1624 - pickTarget(child);
1893 + var maxHeight=0;
1625 1625  
1626 - if(!target)return;
1627 -
1628 - entries.push({
1629 - target:target,
1630 - rect:
1631 - target.getBoundingClientRect()
1895 + group.items.forEach(function(item){
1896 + maxHeight=
1897 + Math.max(
1898 + maxHeight,
1899 + item
1900 + .getBoundingClientRect()
1901 + .height
1902 + );
1632 1632   });
1633 - });
1634 1634  
1635 - groupRows(
1636 - entries
1637 - ).forEach(function(group){
1638 - if(!validRow(group))return;
1905 + maxHeight=
1906 + Math.ceil(maxHeight);
1639 1639  
1640 - var targets=
1641 - group.entries.map(function(entry){
1642 - return entry.target;
1643 - });
1908 + group.items.forEach(function(item){
1909 + saveStyle(
1910 + item,
1911 + originalHeight,
1912 + "min-height"
1913 + );
1644 1644  
1645 - if(
1646 - !targets.some(function(el){
1647 - return !touched.has(el);
1648 - })
1649 - ){
1650 - return;
1651 - }
1915 + item.style.setProperty(
1916 + "min-height",
1917 + maxHeight+"px"
1918 + );
1652 1652  
1653 - if(applyRow(group)){
1654 - targets.forEach(function(el){
1655 - touched.add(el);
1656 - });
1657 - }
1920 + item.setAttribute(
1921 + "data-sn-master-equal-height",
1922 + "1"
1923 + );
1924 +
1925 + managedHeight.add(item);
1926 + });
1658 1658   });
1659 1659   });
1929 + });
1930 + }
1660 1660  
1661 - lastWidth=width;
1662 - hasApplied=true;
1932 + /* =======================================================
1933 + RUN / RESPONSIVE SCHEDULING
1934 + ======================================================= */
1935 +
1936 + function run(){
1937 + if(running)return;
1938 +
1939 + running=true;
1940 +
1941 + try{
1942 + resetRuntime();
1943 + applyPlaceholderBadge();
1944 + propagateDetailAccents();
1945 +
1946 + var headers=
1947 + applyOverviewPalette();
1948 +
1949 + makeThreeLineAreaLabels();
1950 + makeFilledRedOrangeCTAsBorderless();
1951 +
1952 + if(
1953 + window.innerWidth>
1954 + MOBILE_MAX
1955 + ){
1956 + alignOverviewCards(
1957 + headers
1958 + );
1959 +
1960 + equaliseDetailGrids();
1961 + }
1663 1663   }finally{
1664 - applying=false;
1963 + running=false;
1665 1665   }
1666 1666   }
1667 1667  
1668 - function resize(){
1967 + function onResize(){
1669 1669   if(resizeTimer){
1670 1670   clearTimeout(
1671 1671   resizeTimer
... ... @@ -1676,19 +1676,40 @@
1676 1676   setTimeout(
1677 1677   function(){
1678 1678   resizeTimer=0;
1679 - calculate(false);
1978 + run();
1680 1680   },
1681 1681   RESIZE_DEBOUNCE
1682 1682   );
1683 1683   }
1684 1684  
1685 - function waitImages(){
1984 + async function waitForReady(){
1985 + if(
1986 + document.readyState!=="complete"
1987 + ){
1988 + await new Promise(function(resolve){
1989 + window.addEventListener(
1990 + "load",
1991 + resolve,
1992 + {once:true}
1993 + );
1994 + });
1995 + }
1996 +
1997 + if(
1998 + document.fonts&&
1999 + document.fonts.ready
2000 + ){
2001 + try{
2002 + await document.fonts.ready;
2003 + }catch(error){}
2004 + }
2005 +
1686 1686   var images=
1687 1687   Array.from(
1688 1688   root.querySelectorAll("img")
1689 1689   );
1690 1690  
1691 - return Promise.all(
2011 + await Promise.all(
1692 1692   images.map(function(img){
1693 1693   if(img.complete){
1694 1694   return Promise.resolve();
... ... @@ -1713,46 +1713,89 @@
1713 1713   });
1714 1714   })
1715 1715   );
1716 - }
1717 1717  
1718 - async function initial(){
1719 - if(
1720 - document.readyState!==
1721 - "complete"
1722 - ){
1723 - await new Promise(function(resolve){
1724 - addEventListener(
1725 - "load",
1726 - resolve,
1727 - {once:true}
1728 - );
1729 - });
1730 - }
1731 -
1732 - if(
1733 - document.fonts&&
1734 - document.fonts.ready
1735 - ){
1736 - try{
1737 - await document.fonts.ready;
1738 - }catch(error){}
1739 - }
1740 -
1741 - await waitImages();
1742 -
1743 - // Exactly one initial layout calculation.
1744 - calculate(true);
2037 + run();
1745 1745   }
1746 1746  
1747 - addEventListener(
2040 + window.addEventListener(
1748 1748   "resize",
1749 - resize,
2042 + onResize,
1750 1750   {passive:true}
1751 1751   );
1752 1752  
1753 - initial();
2046 + waitForReady();
1754 1754  })();
1755 1755  </script>
1756 1756  
1757 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
1758 -{{/html}}\n
2050 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
2051 +{{/html}}
2052 +
2053 +{{html clean="false"}}
2054 +<!-- ARSN_PHASE_CTA_MOBILE_EDGE_FIX_V3_START -->
2055 +<style data-arsn-phase-cta-mobile-edge-fix="3">
2056 +@media (max-width:767px){
2057 +
2058 + /* Remove the white side gutters around the three phase CTAs. */
2059 + #xwikicontent .arsn-phase-cta-wrap{
2060 + box-sizing:border-box!important;
2061 + width:calc(100% + 2px)!important;
2062 + max-width:none!important;
2063 + margin:14px -1px -1px -1px!important;
2064 + padding:0!important;
2065 + border:0!important;
2066 + border-left:0!important;
2067 + box-shadow:none!important;
2068 + background:transparent!important;
2069 + }
2070 +
2071 + /* Full-width orange CTA; no extra border/shadow. */
2072 + #xwikicontent a.arsn-phase-cta{
2073 + display:flex!important;
2074 + align-items:center!important;
2075 + justify-content:center!important;
2076 + gap:8px!important;
2077 +
2078 + box-sizing:border-box!important;
2079 + width:100%!important;
2080 + max-width:none!important;
2081 + min-width:0!important;
2082 +
2083 + margin:0!important;
2084 + padding:12px 14px!important;
2085 +
2086 + border:0!important;
2087 + border-left:0!important;
2088 + border-right:0!important;
2089 + border-top:0!important;
2090 + border-bottom:0!important;
2091 + box-shadow:none!important;
2092 +
2093 + border-radius:8px!important;
2094 +
2095 + text-align:center!important;
2096 + text-align-last:center!important;
2097 + text-justify:auto!important;
2098 + word-spacing:normal!important;
2099 + white-space:normal!important;
2100 + }
2101 +
2102 + /* Keep an XWiki external-link icon on the same line/flex row. */
2103 + #xwikicontent a.arsn-phase-cta::after{
2104 + flex:0 0 auto!important;
2105 + margin-left:2px!important;
2106 + }
2107 +
2108 + #xwikicontent a.arsn-phase-cta > .fa,
2109 + #xwikicontent a.arsn-phase-cta > .icon,
2110 + #xwikicontent a.arsn-phase-cta > .external-link-icon,
2111 + #xwikicontent a.arsn-phase-cta > [class*="external"]{
2112 + position:static!important;
2113 + display:inline-block!important;
2114 + flex:0 0 auto!important;
2115 + margin:0!important;
2116 + }
2117 +}
2118 +</style>
2119 +<!-- ARSN_PHASE_CTA_MOBILE_EDGE_FIX_V3_END -->
2120 +{{/html}}
2121 +