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

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