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

From version 40.1
edited by Veronika Kocher
on Thursday, 03 Sep 2026 15:57
Change comment: There is no comment for this version
To version 39.23
edited by Veronika Kocher
on Thursday, 03 Sep 2026 10:09
Change comment: There is no comment for this version

Summary

Details

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