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

From version 41.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,14 +2,18 @@
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  
15 +
16 +
13 13  {{html clean="false"}}
14 14  <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);">
15 15   <h2 style="font-size:20px;margin:0 0 6px 0;color:#35312d;">Search the Art &amp; Research Services Navigator</h2>
... ... @@ -635,13 +635,12 @@
635 635  {{/info}}
636 636  )))
637 637  
638 -{{html clean="false"}}
639 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
642 +\n\n
643 +\n\n{{html clean="false"}}
644 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
640 640  
641 -<style data-sn-service-navigator-master="1">
642 -/* =========================================================
643 - MASTER TYPOGRAPHY
644 - ========================================================= */
646 +<style data-sn-horizontal-box-harmonizer="7">
647 +/* ---------- Typography: never justify headings ---------- */
645 645  #xwikicontent h1,
646 646  #xwikicontent h2,
647 647  #xwikicontent h3,
... ... @@ -663,105 +663,88 @@
663 663   word-spacing:normal!important;
664 664  }
665 665  
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{
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"]{
694 694   box-sizing:border-box!important;
695 - border-left:4px solid #21b6d7!important;
696 - 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;
697 697   text-align:left!important;
687 + text-justify:auto!important;
698 698   word-spacing:normal!important;
689 + box-shadow:none!important;
699 699  }
700 700  
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,
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,
708 708  #xwikicontent .errormessage{
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;
712 + --sn-callout-accent:#e94b13;
713 + background:#fff1ec!important;
714 714  }
715 715  
716 -[data-sn-master-equal-height],
717 -[data-sn-master-first-row]{
718 - 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;
719 719  }
720 720  
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;
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;
739 739  }
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;
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;
751 751  }
752 752  </style>
753 753  
754 -<script data-sn-service-navigator-master="1">
739 +<script data-sn-horizontal-box-harmonizer="7">
755 755  (function(){
756 756   "use strict";
757 757  
758 - var PAGE_KIND="overview";
759 - var PLACEHOLDER=false;
760 - var PLACEHOLDER_LABEL="COMING SOON";
761 -
762 762   var MOBILE_MAX=767;
763 763   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;
764 764   var RESIZE_DEBOUNCE=220;
750 + var MIN_WIDTH_CHANGE=2;
765 765  
766 766   var root=
767 767   document.getElementById("xwikicontent")||
... ... @@ -771,114 +771,142 @@
771 771  
772 772   if(!root)return;
773 773  
774 - var managedHeight=new Set();
775 - var managedMargin=new Set();
776 - var originalHeight=new WeakMap();
777 - var originalMargin=new WeakMap();
760 + var heightManaged=new Set();
761 + var sectionManaged=new Set();
762 + var contentManaged=new Set();
778 778  
764 + var originalMinHeight=new WeakMap();
765 + var originalMarginTop=new WeakMap();
766 +
779 779   var resizeTimer=0;
780 - var running=false;
768 + var lastWidth=-1;
769 + var hasApplied=false;
770 + var applying=false;
781 781  
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 - ]
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;
843 843   }
844 - ];
845 845  
846 - function num(value){
847 - var n=parseFloat(value);
848 - 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 + );
849 849   }
850 850  
851 - function norm(value){
852 - return String(value||"")
798 + function normalizeText(text){
799 + return String(text||"")
853 853   .replace(/\s+/g," ")
854 854   .trim()
855 855   .toUpperCase();
856 856   }
857 857  
858 - function visible(el){
859 - 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 + }
860 860  
861 - var style=getComputedStyle(el);
862 - var rect=el.getBoundingClientRect();
814 + /* ---------- Custom coloured callouts ---------- */
863 863  
816 + function nativeCallout(el){
817 + var c=
818 + typeof el.className==="string"
819 + ? el.className.toLowerCase()
820 + : "";
821 +
864 864   return (
865 - style.display!=="none"&&
866 - style.visibility!=="hidden"&&
867 - rect.width>20&&
868 - rect.height>4
823 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c)
869 869   );
870 870   }
871 871  
872 - 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){
873 873   if(map.has(el))return;
874 874  
875 875   map.set(el,{
876 - value:el.style.getPropertyValue(property),
877 - priority:el.style.getPropertyPriority(property)
884 + value:
885 + el.style.getPropertyValue(
886 + property
887 + ),
888 + priority:
889 + el.style.getPropertyPriority(
890 + property
891 + )
878 878   });
879 879   }
880 880  
881 - function restoreStyle(el,map,property){
895 + function restoreOriginal(el,map,property){
882 882   var original=map.get(el);
883 883  
884 884   if(original&&original.value){
... ... @@ -888,1069 +888,770 @@
888 888   original.priority||""
889 889   );
890 890   }else{
891 - el.style.removeProperty(property);
905 + el.style.removeProperty(
906 + property
907 + );
892 892   }
893 893   }
894 894  
895 895   function resetRuntime(){
896 - managedHeight.forEach(function(el){
897 - restoreStyle(
912 + heightManaged.forEach(function(el){
913 + restoreOriginal(
898 898   el,
899 - originalHeight,
915 + originalMinHeight,
900 900   "min-height"
901 901   );
918 +
902 902   el.removeAttribute(
903 - "data-sn-master-equal-height"
920 + "data-sn-equal-height-managed"
904 904   );
905 905   });
906 906  
907 - managedMargin.forEach(function(el){
908 - restoreStyle(
924 + sectionManaged.forEach(function(el){
925 + restoreOriginal(
909 909   el,
910 - originalMargin,
927 + originalMarginTop,
911 911   "margin-top"
912 912   );
930 +
913 913   el.removeAttribute(
914 - "data-sn-master-first-row"
932 + "data-sn-first-section-aligned"
915 915   );
916 916   });
917 917  
918 - managedHeight.clear();
919 - managedMargin.clear();
920 - }
936 + contentManaged.forEach(function(el){
937 + restoreOriginal(
938 + el,
939 + originalMarginTop,
940 + "margin-top"
941 + );
921 921  
922 - function themeFor(text){
923 - var value=norm(text);
943 + el.removeAttribute(
944 + "data-sn-first-content-aligned"
945 + );
946 + });
924 924  
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];
928 -
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 - }
939 -
940 - return null;
948 + heightManaged.clear();
949 + sectionManaged.clear();
950 + contentManaged.clear();
941 941   }
942 942  
943 - /* =======================================================
944 - BORDERLESS FILLED RED/ORANGE CTA BUTTONS
945 - ======================================================= */
953 + /* ---------- Card detection ---------- */
946 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 - );
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);
953 953   }
954 954  
955 - function makeFilledRedOrangeCTAsBorderless(){
956 - 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 + }
957 957  
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;
972 + var s=getComputedStyle(el);
973 + var r=el.getBoundingClientRect();
964 964  
965 - var style=getComputedStyle(el);
966 - var rgb=parseRGB(style.backgroundColor);
975 + var border=
976 + num(s.borderTopWidth)+
977 + num(s.borderRightWidth)+
978 + num(s.borderBottomWidth)+
979 + num(s.borderLeftWidth);
967 967  
968 - 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 + );
969 969  
970 - if(
971 - colourDistance(
972 - rgb,
973 - RED_ORANGE
974 - )>55
975 - ){
976 - return;
977 - }
988 + var bg=
989 + s.backgroundColor&&
990 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
991 + s.backgroundColor!=="transparent";
978 978  
979 - var rect=el.getBoundingClientRect();
993 + var shadow=
994 + s.boxShadow&&
995 + s.boxShadow!=="none";
980 980  
981 - if(
982 - rect.width<80||
983 - rect.height<24
984 - ){
985 - return;
986 - }
997 + return (
998 + namedLikeBox(el)||
999 + border>=1||
1000 + (bg&&radius>=3)||
1001 + (shadow&&r.width>=180)
1002 + );
1003 + }
987 987  
988 - el.style.setProperty(
989 - "border",
990 - "none",
991 - "important"
992 - );
1005 + function pickTarget(child){
1006 + if(!visible(child,MIN_W,MIN_H))return null;
993 993  
994 - el.style.setProperty(
995 - "border-left",
996 - "none",
997 - "important"
998 - );
1008 + if(boxLike(child))return child;
999 999  
1000 - el.style.setProperty(
1001 - "border-top",
1002 - "none",
1003 - "important"
1004 - );
1010 + var cr=child.getBoundingClientRect();
1011 + var q=[];
1005 1005  
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 - );
1013 + Array.from(child.children||[]).forEach(function(el){
1014 + q.push({el:el,depth:1});
1023 1023   });
1024 - }
1025 1025  
1026 - /* =======================================================
1027 - FULL-WIDTH THREE-LINE AREA LABELS
1028 - ======================================================= */
1017 + var best=null;
1018 + var bestScore=-Infinity;
1029 1029  
1030 - function compactText(value){
1031 - return String(value||"")
1032 - .replace(/\s+/g," ")
1033 - .trim();
1034 - }
1020 + while(q.length){
1021 + var item=q.shift();
1022 + var el=item.el;
1035 1035  
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 - }
1024 + if(!visible(el,MIN_W,MIN_H))continue;
1049 1049  
1050 - var number=
1051 - label.querySelector(
1052 - ":scope > .arsn-area-number"
1053 - );
1026 + var r=el.getBoundingClientRect();
1054 1054  
1055 - var action=
1056 - label.querySelector(
1057 - ":scope > .arsn-area-action"
1058 - );
1059 -
1060 1060   if(
1061 - !number||
1062 - !action
1029 + r.width>=cr.width*.68&&
1030 + boxLike(el)
1063 1063   ){
1064 - return;
1065 - }
1032 + var widthFit=
1033 + 1-Math.min(
1034 + 1,
1035 + Math.abs(cr.width-r.width)/
1036 + Math.max(1,cr.width)
1037 + );
1066 1066  
1067 - var clone=
1068 - label.cloneNode(true);
1039 + var topFit=
1040 + 1-Math.min(
1041 + 1,
1042 + Math.abs(cr.top-r.top)/100
1043 + );
1069 1069  
1070 - var cloneNumber=
1071 - clone.querySelector(
1072 - ":scope > .arsn-area-number"
1073 - );
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;
1074 1074  
1075 - var cloneAction=
1076 - clone.querySelector(
1077 - ":scope > .arsn-area-action"
1078 - );
1079 -
1080 - if(cloneNumber){
1081 - cloneNumber.remove();
1051 + if(score>bestScore){
1052 + best=el;
1053 + bestScore=score;
1054 + }
1082 1082   }
1083 1083  
1084 - if(cloneAction){
1085 - 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 + });
1086 1086   }
1065 + }
1087 1087  
1088 - var titleText=
1089 - compactText(
1090 - clone.textContent
1091 - );
1067 + return best;
1068 + }
1092 1092  
1093 - if(!titleText){
1094 - return;
1095 - }
1070 + function groupRows(entries){
1071 + var groups=[];
1096 1096  
1097 - var numberNode=
1098 - number.cloneNode(true);
1099 -
1100 - var actionNode=
1101 - action.cloneNode(true);
1102 -
1103 - var titleNode=
1104 - document.createElement(
1105 - "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
1106 1106   );
1080 + })
1081 + .forEach(function(entry){
1082 + var group=null;
1107 1107  
1108 - titleNode.className=
1109 - "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 + }
1110 1110  
1111 - titleNode.textContent=
1112 - titleText;
1096 + if(!group){
1097 + group={
1098 + top:entry.rect.top,
1099 + entries:[]
1100 + };
1101 + groups.push(group);
1102 + }
1113 1113  
1114 - while(label.firstChild){
1115 - label.removeChild(
1116 - label.firstChild
1117 - );
1118 - }
1104 + group.entries.push(entry);
1105 + });
1119 1119  
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 - });
1107 + return groups;
1162 1162   }
1163 1163  
1164 - /* =======================================================
1165 - PLACEHOLDER BADGE
1166 - ======================================================= */
1110 + function validRow(group){
1111 + if(group.entries.length<2)return false;
1167 1167  
1168 - function applyPlaceholderBadge(){
1169 - 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;});
1170 1170  
1171 1171   if(
1172 - document.querySelector(
1173 - ".sn-coming-soon-badge"
1174 - )
1119 + lefts[lefts.length-1]-
1120 + lefts[0]<
1121 + 80
1175 1175   ){
1176 - return;
1123 + return false;
1177 1177   }
1178 1178  
1179 - var title=
1180 - document.querySelector(
1181 - "#document-title"
1182 - )||
1183 - document.querySelector(
1184 - "h1"
1185 - );
1126 + var widths=
1127 + group.entries
1128 + .map(function(e){return e.rect.width;})
1129 + .filter(function(w){return w>0;});
1186 1186  
1187 - if(!title)return;
1131 + if(widths.length<2)return false;
1188 1188  
1189 - var badge=
1190 - document.createElement(
1191 - "span"
1192 - );
1133 + var minW=
1134 + Math.min.apply(Math,widths);
1193 1193  
1194 - badge.className=
1195 - "sn-coming-soon-badge";
1136 + var maxW=
1137 + Math.max.apply(Math,widths);
1196 1196  
1197 - badge.textContent=
1198 - PLACEHOLDER_LABEL;
1199 -
1200 - badge.setAttribute(
1201 - "aria-label",
1202 - PLACEHOLDER_LABEL
1139 + return (
1140 + maxW/
1141 + Math.max(1,minW)<=
1142 + 1.9
1203 1203   );
1144 + }
1204 1204  
1205 - title.appendChild(
1206 - 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"
1207 1207   );
1208 1208   }
1209 1209  
1210 - /* =======================================================
1211 - DETAIL PAGE OWN-ACCENT PROPAGATION
1212 - ======================================================= */
1166 + function findKnownBar(card){
1167 + var cardRect=
1168 + card.getBoundingClientRect();
1213 1213  
1214 - function parseRGB(value){
1215 - var match=String(value||"").match(
1216 - /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
1217 - );
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;
1218 1218  
1219 - if(!match)return null;
1180 + var r=el.getBoundingClientRect();
1220 1220  
1221 - return [
1222 - Number(match[1]),
1223 - Number(match[2]),
1224 - Number(match[3])
1225 - ];
1226 - }
1182 + var rel=
1183 + r.top-
1184 + cardRect.top;
1227 1227  
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 - );
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;
1234 1234   }
1235 1235  
1236 - function paletteMatch(cssColor){
1237 - var rgb=parseRGB(cssColor);
1202 + function alignKnownBars(cards){
1203 + var rows=
1204 + cards.map(function(card){
1205 + var bar=
1206 + findKnownBar(card);
1238 1238  
1239 - if(!rgb)return null;
1208 + if(!bar)return null;
1240 1240  
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 - ];
1210 + var cr=
1211 + card.getBoundingClientRect();
1247 1247  
1248 - var best=null;
1249 - var bestDistance=Infinity;
1213 + var br=
1214 + bar.getBoundingClientRect();
1250 1250  
1251 - palette.forEach(function(item){
1252 - var d=distance(rgb,item.rgb);
1216 + return {
1217 + bar:bar,
1218 + relativeTop:
1219 + br.top-
1220 + cr.top
1221 + };
1222 + });
1253 1253  
1254 - if(d<bestDistance){
1255 - best=item;
1256 - bestDistance=d;
1257 - }
1258 - });
1224 + if(
1225 + rows.some(function(row){
1226 + return !row;
1227 + })
1228 + ){
1229 + return false;
1230 + }
1259 1259  
1260 - return bestDistance<=30
1261 - ?best
1262 - :null;
1263 - }
1232 + var target=
1233 + Math.max.apply(
1234 + Math,
1235 + rows.map(function(row){
1236 + return row.relativeTop;
1237 + })
1238 + );
1264 1264  
1265 - function propagateDetailAccents(){
1266 - if(PAGE_KIND!=="detail")return;
1240 + rows.forEach(function(row){
1241 + var delta=
1242 + target-
1243 + row.relativeTop;
1267 1267  
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;
1245 + if(delta<=1)return;
1275 1275  
1276 - var style=getComputedStyle(el);
1247 + saveOriginal(
1248 + row.bar,
1249 + originalMarginTop,
1250 + "margin-top"
1251 + );
1277 1277  
1278 - if(
1279 - num(style.borderTopWidth)>=2
1280 - ){
1281 - var match=
1282 - paletteMatch(
1283 - style.borderTopColor
1284 - );
1253 + var current=
1254 + num(
1255 + getComputedStyle(
1256 + row.bar
1257 + ).marginTop
1258 + );
1285 1285  
1286 - if(match){
1287 - el.style.setProperty(
1288 - "border-left",
1289 - "4px solid "+match.hex,
1290 - "important"
1291 - );
1292 - }
1293 - }
1294 - });
1260 + row.bar.style.setProperty(
1261 + "margin-top",
1262 + (
1263 + current+
1264 + delta
1265 + )+"px"
1266 + );
1295 1295  
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;
1304 -
1305 - el.style.setProperty(
1306 - "border-left",
1307 - "4px solid #e94b13",
1308 - "important"
1268 + row.bar.setAttribute(
1269 + "data-sn-first-section-aligned",
1270 + "7"
1309 1309   );
1310 - });
1311 1311  
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"
1273 + sectionManaged.add(
1274 + row.bar
1324 1324   );
1325 1325   });
1277 +
1278 + return true;
1326 1326   }
1327 1327  
1328 - /* =======================================================
1329 - OVERVIEW SEMANTIC THEME PALETTE
1330 - ======================================================= */
1281 + /* ---------- Generic first content after heading ---------- */
1331 1331  
1332 - function smallestThemeHeaders(){
1333 - return Array.from(
1334 - root.querySelectorAll(
1335 - "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 + )
1336 1336   )
1337 - ).filter(function(el){
1338 - if(!visible(el))return false;
1339 - if(!themeFor(el.textContent))return false;
1293 + .filter(function(el){
1294 + if(!visible(el,20,8))return false;
1340 1340  
1341 - return !Array.from(
1342 - el.children||[]
1343 - ).some(function(child){
1344 - return !!themeFor(
1345 - 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 + )
1346 1346   );
1310 + })
1311 + .sort(function(a,b){
1312 + return (
1313 + a.getBoundingClientRect().top-
1314 + b.getBoundingClientRect().top
1315 + );
1347 1347   });
1348 - });
1317 +
1318 + return rows[0]||null;
1349 1349   }
1350 1350  
1351 - function findOverviewCard(header){
1352 - var node=header.parentElement;
1353 - var candidates=[];
1321 + function firstContent(card,h){
1322 + if(!h)return null;
1354 1354  
1355 - while(node&&node!==root){
1356 - var rect=node.getBoundingClientRect();
1357 - var style=getComputedStyle(node);
1324 + var cr=
1325 + card.getBoundingClientRect();
1358 1358  
1359 - var border=
1360 - num(style.borderTopWidth)+
1361 - num(style.borderRightWidth)+
1362 - num(style.borderBottomWidth)+
1363 - num(style.borderLeftWidth);
1327 + var hr=
1328 + h.getBoundingClientRect();
1364 1364  
1365 - if(
1366 - rect.width>=220&&
1367 - rect.width<=800&&
1368 - rect.height>=120&&
1369 - border>=1
1370 - ){
1371 - candidates.push(node);
1372 - }
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 + }
1373 1373  
1374 - node=node.parentElement;
1375 - }
1345 + if(!visible(el,30,8))return false;
1376 1376  
1377 - if(!candidates.length)return null;
1347 + var text=
1348 + String(el.textContent||"")
1349 + .replace(/\s+/g," ")
1350 + .trim();
1378 1378  
1379 - candidates.sort(function(a,b){
1380 - return (
1381 - b.getBoundingClientRect().height-
1382 - a.getBoundingClientRect().height
1383 - );
1384 - });
1352 + if(text.length<3)return false;
1385 1385  
1386 - return candidates[0];
1387 - }
1354 + var r=el.getBoundingClientRect();
1388 1388  
1389 - function rowCandidates(link,card){
1390 - var result=[];
1391 - var cardRect=
1392 - card.getBoundingClientRect();
1356 + if(
1357 + r.top<
1358 + hr.bottom-1
1359 + ){
1360 + return false;
1361 + }
1393 1393  
1394 - 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 + }
1395 1395  
1396 - while(node&&node!==card){
1397 - if(visible(node)){
1398 - var rect=
1399 - node.getBoundingClientRect();
1400 -
1401 1401   if(
1402 - rect.height<=105&&
1403 - rect.width>=
1404 - cardRect.width*.50&&
1405 - rect.width<=
1406 - cardRect.width*1.03
1374 + r.height>
1375 + cr.height*.58
1407 1407   ){
1408 - result.push(node);
1377 + return false;
1409 1409   }
1410 - }
1411 1411  
1412 - node=node.parentElement;
1413 - }
1380 + return true;
1381 + })
1382 + .sort(function(a,b){
1383 + var ar=
1384 + a.getBoundingClientRect();
1414 1414  
1415 - return result;
1416 - }
1386 + var br=
1387 + b.getBoundingClientRect();
1417 1417  
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){
1428 1428   return (
1429 - num(
1430 - getComputedStyle(el)
1431 - .borderLeftWidth
1432 - )>=1
1390 + ar.top-br.top||
1391 + ar.height-br.height
1433 1433   );
1434 1434   });
1435 1435  
1436 - var pool=
1437 - bordered.length
1438 - ?bordered
1439 - :candidates;
1395 + return rows[0]||null;
1396 + }
1440 1440  
1441 - pool.sort(function(a,b){
1442 - var ar=
1443 - a.getBoundingClientRect();
1398 + function alignGeneric(cards){
1399 + var rows=
1400 + cards.map(function(card){
1401 + var h=
1402 + heading(card);
1444 1444  
1445 - var br=
1446 - b.getBoundingClientRect();
1404 + var c=
1405 + firstContent(
1406 + card,
1407 + h
1408 + );
1447 1447  
1448 - return (
1449 - ar.left-br.left||
1450 - br.width-ar.width
1451 - );
1452 - });
1410 + if(!h||!c)return null;
1453 1453  
1454 - return pool[0]||link;
1455 - }
1412 + var cr=
1413 + card.getBoundingClientRect();
1456 1456  
1457 - function applyOverviewPalette(){
1458 - if(PAGE_KIND!=="overview"){
1459 - 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;
1460 1460   }
1461 1461  
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 - };
1433 + var target=
1434 + Math.max.apply(
1435 + Math,
1436 + rows.map(function(row){
1437 + return row.relativeTop;
1476 1476   })
1477 - .filter(function(row){
1478 - return !!row.card;
1479 - });
1439 + );
1480 1480  
1481 - var unique=[];
1482 - var seenHeaders=new Set();
1441 + rows.forEach(function(row){
1442 + var delta=
1443 + target-
1444 + row.relativeTop;
1483 1483  
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 - );
1446 + if(delta<=1)return;
1499 1499  
1500 - if(!seenHeaders.has(key)){
1501 - seenHeaders.add(key);
1502 - unique.push(row);
1503 - }
1504 - });
1505 -
1506 - unique.forEach(function(row){
1507 - var headerRect=
1508 - row.el
1509 - .getBoundingClientRect();
1510 -
1511 - row.el.style.setProperty(
1512 - "background",
1513 - row.theme.bg,
1514 - "important"
1448 + saveOriginal(
1449 + row.content,
1450 + originalMarginTop,
1451 + "margin-top"
1515 1515   );
1516 1516  
1517 - row.el.style.setProperty(
1518 - "color",
1519 - row.theme.text,
1520 - "important"
1521 - );
1454 + var current=
1455 + num(
1456 + getComputedStyle(
1457 + row.content
1458 + ).marginTop
1459 + );
1522 1522  
1523 - row.el.style.setProperty(
1524 - "text-align",
1525 - "left",
1526 - "important"
1461 + row.content.style.setProperty(
1462 + "margin-top",
1463 + (
1464 + current+
1465 + delta
1466 + )+"px"
1527 1527   );
1528 1528  
1529 - row.el.style.setProperty(
1530 - "word-spacing",
1531 - "normal",
1532 - "important"
1469 + row.content.setAttribute(
1470 + "data-sn-first-content-aligned",
1471 + "7"
1533 1533   );
1534 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 - });
1474 + contentManaged.add(
1475 + row.content
1476 + );
1614 1614   });
1615 1615  
1616 - return unique;
1479 + return true;
1617 1617   }
1618 1618  
1619 - /* =======================================================
1620 - OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1621 - ======================================================= */
1482 + function applyRow(group){
1483 + if(!validRow(group))return false;
1622 1622  
1623 - function alignOverviewCards(headers){
1624 - if(
1625 - PAGE_KIND!=="overview"||
1626 - window.innerWidth<=MOBILE_MAX
1627 - ){
1628 - return;
1629 - }
1630 -
1631 1631   var cards=[];
1632 1632   var seen=new Set();
1633 1633  
1634 - headers.forEach(function(row){
1635 - if(!seen.has(row.card)){
1636 - seen.add(row.card);
1637 - 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);
1638 1638   }
1639 1639   });
1640 1640  
1641 - if(cards.length<2){
1642 - return;
1495 + if(cards.length<2)return false;
1496 +
1497 + if(
1498 + !alignKnownBars(cards)
1499 + ){
1500 + alignGeneric(cards);
1643 1643   }
1644 1644  
1645 - // Group cards by actual top position.
1646 - var groups=[];
1503 + var maxHeight=0;
1647 1647  
1648 1648   cards.forEach(function(card){
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);
1506 + maxHeight=
1507 + Math.max(
1508 + maxHeight,
1509 + card.getBoundingClientRect().height
1510 + );
1674 1674   });
1675 1675  
1676 - groups.forEach(function(group){
1677 - if(group.cards.length<2){
1678 - return;
1679 - }
1513 + maxHeight=
1514 + Math.ceil(
1515 + maxHeight
1516 + );
1680 1680  
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 - });
1518 + if(maxHeight<MIN_H)return false;
1698 1698  
1699 - return candidates.length
1700 - ?candidates[0]
1701 - :null;
1702 - });
1520 + cards.forEach(function(card){
1521 + saveOriginal(
1522 + card,
1523 + originalMinHeight,
1524 + "min-height"
1525 + );
1703 1703  
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 - );
1527 + card.style.setProperty(
1528 + "min-height",
1529 + maxHeight+"px"
1530 + );
1723 1723  
1724 - firstHeaders.forEach(function(row){
1725 - var relativeTop=
1726 - row.el
1727 - .getBoundingClientRect()
1728 - .top-
1729 - row.card
1730 - .getBoundingClientRect()
1731 - .top;
1532 + card.setAttribute(
1533 + "data-sn-equal-height-managed",
1534 + "7"
1535 + );
1732 1732  
1733 - var delta=
1734 - targetTop-relativeTop;
1537 + heightManaged.add(card);
1538 + });
1735 1735  
1736 - if(delta>1){
1737 - saveStyle(
1738 - row.el,
1739 - originalMargin,
1740 - "margin-top"
1741 - );
1540 + return true;
1541 + }
1742 1742  
1743 - var current=
1744 - num(
1745 - getComputedStyle(
1746 - row.el
1747 - ).marginTop
1748 - );
1543 + function calculate(force){
1544 + if(applying)return;
1749 1749  
1750 - row.el.style.setProperty(
1751 - "margin-top",
1752 - (
1753 - current+delta
1754 - )+"px"
1755 - );
1546 + var width=
1547 + Math.round(
1548 + window.innerWidth
1549 + );
1756 1756  
1757 - row.el.setAttribute(
1758 - "data-sn-master-first-row",
1759 - "1"
1760 - );
1551 + var meaningful=
1552 + lastWidth<0||
1553 + Math.abs(
1554 + width-
1555 + lastWidth
1556 + )>=
1557 + MIN_WIDTH_CHANGE;
1761 1761  
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(){
1813 1813   if(
1814 - PAGE_KIND!=="detail"||
1815 - window.innerWidth<=MOBILE_MAX
1560 + hasApplied&&
1561 + !force&&
1562 + !meaningful
1816 1816   ){
1817 1817   return;
1818 1818   }
1819 1819  
1820 - var selectors=[
1821 - ".arsn-grid",
1822 - ".arsn-grid-2",
1823 - ".arsn-grid-3",
1824 - ".dmp-grid",
1825 - ".ido-grid",
1826 - ".pp-grid"
1827 - ];
1567 + applying=true;
1828 1828  
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);
1569 + try{
1570 + harmoniseCustomCallouts();
1837 1837  
1838 - if(children.length<2){
1839 - return;
1572 + if(width<=MOBILE_MAX){
1573 + if(hasApplied){
1574 + resetRuntime();
1840 1840   }
1841 1841  
1842 - var groups=[];
1577 + hasApplied=false;
1578 + lastWidth=width;
1579 + return;
1580 + }
1843 1843  
1844 - children.forEach(function(child){
1845 - var top=
1846 - child
1847 - .getBoundingClientRect()
1848 - .top;
1582 + if(hasApplied){
1583 + resetRuntime();
1584 + }
1849 1849  
1850 - 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 + });
1851 1851  
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 - }
1604 + var touched=
1605 + new Set();
1862 1862  
1863 - if(!group){
1864 - group={
1865 - top:top,
1866 - items:[]
1867 - };
1868 - groups.push(group);
1869 - }
1607 + parents.forEach(function(parent){
1608 + var entries=[];
1870 1870  
1871 - group.items.push(child);
1872 - });
1873 -
1874 - groups.forEach(function(group){
1875 - 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 + ){
1876 1876   return;
1877 1877   }
1878 1878  
1879 - var maxHeight=0;
1623 + var target=
1624 + pickTarget(child);
1880 1880  
1881 - group.items.forEach(function(item){
1882 - maxHeight=
1883 - Math.max(
1884 - maxHeight,
1885 - item
1886 - .getBoundingClientRect()
1887 - .height
1888 - );
1626 + if(!target)return;
1627 +
1628 + entries.push({
1629 + target:target,
1630 + rect:
1631 + target.getBoundingClientRect()
1889 1889   });
1633 + });
1890 1890  
1891 - maxHeight=
1892 - Math.ceil(maxHeight);
1635 + groupRows(
1636 + entries
1637 + ).forEach(function(group){
1638 + if(!validRow(group))return;
1893 1893  
1894 - group.items.forEach(function(item){
1895 - saveStyle(
1896 - item,
1897 - originalHeight,
1898 - "min-height"
1899 - );
1640 + var targets=
1641 + group.entries.map(function(entry){
1642 + return entry.target;
1643 + });
1900 1900  
1901 - item.style.setProperty(
1902 - "min-height",
1903 - maxHeight+"px"
1904 - );
1645 + if(
1646 + !targets.some(function(el){
1647 + return !touched.has(el);
1648 + })
1649 + ){
1650 + return;
1651 + }
1905 1905  
1906 - item.setAttribute(
1907 - "data-sn-master-equal-height",
1908 - "1"
1909 - );
1910 -
1911 - managedHeight.add(item);
1912 - });
1653 + if(applyRow(group)){
1654 + targets.forEach(function(el){
1655 + touched.add(el);
1656 + });
1657 + }
1913 1913   });
1914 1914   });
1915 - });
1916 - }
1917 1917  
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 - }
1661 + lastWidth=width;
1662 + hasApplied=true;
1948 1948   }finally{
1949 - running=false;
1664 + applying=false;
1950 1950   }
1951 1951   }
1952 1952  
1953 - function onResize(){
1668 + function resize(){
1954 1954   if(resizeTimer){
1955 1955   clearTimeout(
1956 1956   resizeTimer
... ... @@ -1961,40 +1961,19 @@
1961 1961   setTimeout(
1962 1962   function(){
1963 1963   resizeTimer=0;
1964 - run();
1679 + calculate(false);
1965 1965   },
1966 1966   RESIZE_DEBOUNCE
1967 1967   );
1968 1968   }
1969 1969  
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 -
1685 + function waitImages(){
1992 1992   var images=
1993 1993   Array.from(
1994 1994   root.querySelectorAll("img")
1995 1995   );
1996 1996  
1997 - await Promise.all(
1691 + return Promise.all(
1998 1998   images.map(function(img){
1999 1999   if(img.complete){
2000 2000   return Promise.resolve();
... ... @@ -2019,20 +2019,46 @@
2019 2019   });
2020 2020   })
2021 2021   );
1716 + }
2022 2022  
2023 - 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);
2024 2024   }
2025 2025  
2026 - window.addEventListener(
1747 + addEventListener(
2027 2027   "resize",
2028 - onResize,
1749 + resize,
2029 2029   {passive:true}
2030 2030   );
2031 2031  
2032 - waitForReady();
1753 + initial();
2033 2033  })();
2034 2034  </script>
2035 2035  
2036 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
2037 -{{/html}}
2038 -
1757 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
1758 +{{/html}}\n