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