Änderungen von Dokument Prepare

Zuletzt geändert von Veronika Kocher am Freitag, 18 Sep. 2026 16:47

Von Version 1.9
bearbeitet von Veronika Kocher
am Donnerstag, 03 Sep. 2026 13:04
Änderungskommentar: Es gibt keinen Kommentar für diese Version
Auf Version 1.8
bearbeitet von Veronika Kocher
am Donnerstag, 03 Sep. 2026 10:09
Änderungskommentar: Es gibt keinen Kommentar für diese Version

Zusammenfassung

Details

Seiteneigenschaften
Inhalt
... ... @@ -483,13 +483,12 @@
483 483  </div>
484 484  {{/html}}
485 485  
486 -{{html clean="false"}}
487 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
486 +\n\n
487 +\n\n{{html clean="false"}}
488 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
488 488  
489 -<style data-sn-service-navigator-master="1">
490 -/* =========================================================
491 - MASTER TYPOGRAPHY
492 - ========================================================= */
490 +<style data-sn-horizontal-box-harmonizer="7">
491 +/* ---------- Typography: never justify headings ---------- */
493 493  #xwikicontent h1,
494 494  #xwikicontent h2,
495 495  #xwikicontent h3,
... ... @@ -511,73 +511,88 @@
511 511   word-spacing:normal!important;
512 512  }
513 513  
514 -/* =========================================================
515 - COMING SOON / IN VORBEREITUNG
516 - ========================================================= */
517 -.sn-coming-soon-badge{
518 - display:inline-block;
519 - vertical-align:middle;
520 - margin-left:10px;
521 - padding:4px 8px;
522 - border-radius:14px;
523 - border:1px solid #efd9cc;
524 - background:#fff4ee;
525 - color:#8a4d36;
526 - font-size:11px;
527 - font-weight:700;
528 - letter-spacing:.055em;
529 - line-height:1.2;
530 - white-space:nowrap;
531 -}
532 -
533 -/* =========================================================
534 - NATIVE / DETAIL CALLOUT GEOMETRY
535 - Preserve existing backgrounds.
536 - ========================================================= */
537 -#xwikicontent .arsn-info,
538 -#xwikicontent .dmp-info,
539 -#xwikicontent .ido-info,
540 -#xwikicontent .pp-info,
541 -#xwikicontent .infomessage{
513 +/* ---------- Native XWiki semantic callouts ---------- */
514 +#xwikicontent .box.infomessage,
515 +#xwikicontent .infomessage,
516 +#xwikicontent .box.warningmessage,
517 +#xwikicontent .warningmessage,
518 +#xwikicontent .box.successmessage,
519 +#xwikicontent .successmessage,
520 +#xwikicontent .box.errormessage,
521 +#xwikicontent .errormessage,
522 +#xwikicontent [data-sn-callout-harmonized="1"]{
542 542   box-sizing:border-box!important;
543 - border-left:4px solid #21b6d7!important;
544 - border-radius:8px;
524 + border-radius:8px!important;
525 + border-top:1px solid rgba(0,0,0,.08)!important;
526 + border-right:1px solid rgba(0,0,0,.08)!important;
527 + border-bottom:1px solid rgba(0,0,0,.08)!important;
528 + border-left:4px solid var(--sn-callout-accent,#21b6d7)!important;
529 + padding:14px 16px!important;
545 545   text-align:left!important;
531 + text-justify:auto!important;
546 546   word-spacing:normal!important;
533 + box-shadow:none!important;
547 547  }
548 548  
549 -#xwikicontent .arsn-warn,
550 -#xwikicontent .dmp-warn,
551 -#xwikicontent .ido-warn,
552 -#xwikicontent .pp-warn,
553 -#xwikicontent .warn,
554 -#xwikicontent .warning,
555 -#xwikicontent .warningmessage,
536 +#xwikicontent .box.infomessage,
537 +#xwikicontent .infomessage{
538 + --sn-callout-accent:#21b6d7;
539 + background:#eaf7fb!important;
540 +}
541 +
542 +#xwikicontent .box.warningmessage,
543 +#xwikicontent .warningmessage{
544 + --sn-callout-accent:#f0aa00;
545 + background:#fff8e7!important;
546 +}
547 +
548 +#xwikicontent .box.successmessage,
549 +#xwikicontent .successmessage{
550 + --sn-callout-accent:#38b76a;
551 + background:#edf9f1!important;
552 +}
553 +
554 +#xwikicontent .box.errormessage,
556 556  #xwikicontent .errormessage{
557 - box-sizing:border-box!important;
558 - border-left:4px solid #e94b13!important;
559 - border-radius:8px;
560 - text-align:left!important;
561 - word-spacing:normal!important;
556 + --sn-callout-accent:#e94b13;
557 + background:#fff1ec!important;
562 562  }
563 563  
564 -[data-sn-master-equal-height],
565 -[data-sn-master-first-row]{
560 +#xwikicontent [data-sn-callout-harmonized="1"] > :first-child,
561 +#xwikicontent .infomessage > :first-child,
562 +#xwikicontent .warningmessage > :first-child,
563 +#xwikicontent .successmessage > :first-child,
564 +#xwikicontent .errormessage > :first-child{
565 + margin-top:0!important;
566 +}
567 +
568 +#xwikicontent [data-sn-callout-harmonized="1"] > :last-child,
569 +#xwikicontent .infomessage > :last-child,
570 +#xwikicontent .warningmessage > :last-child,
571 +#xwikicontent .successmessage > :last-child,
572 +#xwikicontent .errormessage > :last-child{
573 + margin-bottom:0!important;
574 +}
575 +
576 +#xwikicontent [data-sn-equal-height-managed],
577 +#xwikicontent [data-sn-first-section-aligned],
578 +#xwikicontent [data-sn-first-content-aligned]{
566 566   box-sizing:border-box;
567 567  }
568 568  </style>
569 569  
570 -<script data-sn-service-navigator-master="1">
583 +<script data-sn-horizontal-box-harmonizer="7">
571 571  (function(){
572 572   "use strict";
573 573  
574 - var PAGE_KIND="overview";
575 - var PLACEHOLDER=false;
576 - var PLACEHOLDER_LABEL="IN VORBEREITUNG";
577 -
578 578   var MOBILE_MAX=767;
579 579   var ROW_TOLERANCE=6;
589 + var MIN_W=150;
590 + var MIN_H=36;
591 + var MAX_PARENT_CHILDREN=18;
592 + var SEARCH_DEPTH=5;
580 580   var RESIZE_DEBOUNCE=220;
594 + var MIN_WIDTH_CHANGE=2;
581 581  
582 582   var root=
583 583   document.getElementById("xwikicontent")||
... ... @@ -587,114 +587,142 @@
587 587  
588 588   if(!root)return;
589 589  
590 - var managedHeight=new Set();
591 - var managedMargin=new Set();
592 - var originalHeight=new WeakMap();
593 - var originalMargin=new WeakMap();
604 + var heightManaged=new Set();
605 + var sectionManaged=new Set();
606 + var contentManaged=new Set();
594 594  
608 + var originalMinHeight=new WeakMap();
609 + var originalMarginTop=new WeakMap();
610 +
595 595   var resizeTimer=0;
596 - var running=false;
612 + var lastWidth=-1;
613 + var hasApplied=false;
614 + var applying=false;
597 597  
598 - var THEMES=[
599 - {
600 - name:"BLUE",
601 - accent:"#21b6d7",
602 - bg:"#eaf7fb",
603 - text:"#315d68",
604 - labels:[
605 - "HIER STARTEN",
606 - "ENTSCHEIDEN",
607 - "ÜBERPRÜFEN & ANPASSEN",
608 - "START HERE",
609 - "DECIDE",
610 - "REVIEW & ADAPT"
611 - ]
612 - },
613 - {
614 - name:"RED",
615 - accent:"#e94b13",
616 - bg:"#fff1ec",
617 - text:"#8a4d36",
618 - labels:[
619 - "PLANEN & ORGANISIEREN",
620 - "ORGANISIEREN & DOKUMENTIEREN",
621 - "PUBLIZIEREN & PRÄSENTIEREN",
622 - "PLAN & ORGANISE",
623 - "PLAN & ORGANIZE",
624 - "ORGANISE & DOCUMENT",
625 - "ORGANIZE & DOCUMENT",
626 - "PUBLISH & PRESENT"
627 - ]
628 - },
629 - {
630 - name:"YELLOW",
631 - accent:"#f0aa00",
632 - bg:"#fff8e7",
633 - text:"#785b17",
634 - labels:[
635 - "SCHÜTZEN & KLÄREN",
636 - "STANDARDISIEREN & IDENTIFIZIEREN",
637 - "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN",
638 - "PROTECT & CLARIFY",
639 - "STANDARDISE & IDENTIFY",
640 - "STANDARDIZE & IDENTIFY",
641 - "OPEN, REUSE & MAKE FINDABLE"
642 - ]
643 - },
644 - {
645 - name:"GREEN",
646 - accent:"#38b76a",
647 - bg:"#edf9f1",
648 - text:"#3f7451",
649 - labels:[
650 - "INFRASTRUKTUR EINRICHTEN",
651 - "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN",
652 - "SPEICHERN & ZUGRIFF STEUERN",
653 - "REPOSITORIUM, ERHALTEN & ÜBERGEBEN",
654 - "SET UP INFRASTRUCTURE",
655 - "SET UP INFRASTRUCTURE & COLLABORATION",
656 - "STORE & CONTROL ACCESS",
657 - "REPOSITORY, PRESERVE & HAND OVER"
658 - ]
616 + function num(v){
617 + var n=parseFloat(v);
618 + return Number.isFinite(n)?n:0;
619 + }
620 +
621 + function visible(el,minW,minH){
622 + if(!el||el.nodeType!==1)return false;
623 +
624 + var s=getComputedStyle(el);
625 +
626 + if(
627 + s.display==="none"||
628 + s.visibility==="hidden"||
629 + Number(s.opacity)===0
630 + ){
631 + return false;
659 659   }
660 - ];
661 661  
662 - function num(value){
663 - var n=parseFloat(value);
664 - return Number.isFinite(n)?n:0;
634 + var r=el.getBoundingClientRect();
635 +
636 + return (
637 + r.width>=(minW||1)&&
638 + r.height>=(minH||1)
639 + );
665 665   }
666 666  
667 - function norm(value){
668 - return String(value||"")
642 + function normalizeText(text){
643 + return String(text||"")
669 669   .replace(/\s+/g," ")
670 670   .trim()
671 671   .toUpperCase();
672 672   }
673 673  
674 - function visible(el){
675 - if(!el||el.nodeType!==1)return false;
649 + function excluded(el){
650 + return (
651 + !el.matches||
652 + el.matches(
653 + "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]"
654 + )
655 + );
656 + }
676 676  
677 - var style=getComputedStyle(el);
678 - var rect=el.getBoundingClientRect();
658 + /* ---------- Custom coloured callouts ---------- */
679 679  
660 + function nativeCallout(el){
661 + var c=
662 + typeof el.className==="string"
663 + ? el.className.toLowerCase()
664 + : "";
665 +
680 680   return (
681 - style.display!=="none"&&
682 - style.visibility!=="hidden"&&
683 - rect.width>20&&
684 - rect.height>4
667 + /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c)
685 685   );
686 686   }
687 687  
688 - function saveStyle(el,map,property){
671 + function customCallout(el){
672 + if(!visible(el,220,42)||excluded(el))return false;
673 +
674 + var r=el.getBoundingClientRect();
675 +
676 + if(r.height>520)return false;
677 +
678 + var s=getComputedStyle(el);
679 +
680 + var bg=
681 + s.backgroundColor&&
682 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
683 + s.backgroundColor!=="transparent"&&
684 + s.backgroundColor!=="rgb(255, 255, 255)";
685 +
686 + var left=
687 + num(s.borderLeftWidth);
688 +
689 + return (
690 + bg&&
691 + left>=2
692 + );
693 + }
694 +
695 + function harmoniseCustomCallouts(){
696 + Array.from(
697 + root.querySelectorAll(
698 + "div,aside,section"
699 + )
700 + ).forEach(function(el){
701 + if(nativeCallout(el))return;
702 + if(!customCallout(el))return;
703 +
704 + var s=getComputedStyle(el);
705 +
706 + el.setAttribute(
707 + "data-sn-callout-harmonized",
708 + "1"
709 + );
710 +
711 + if(
712 + s.borderLeftColor
713 + ){
714 + el.style.setProperty(
715 + "--sn-callout-accent",
716 + s.borderLeftColor
717 + );
718 + }
719 + });
720 + }
721 +
722 + /* ---------- Restore only values V7 itself changed ---------- */
723 +
724 + function saveOriginal(el,map,property){
689 689   if(map.has(el))return;
690 690  
691 691   map.set(el,{
692 - value:el.style.getPropertyValue(property),
693 - priority:el.style.getPropertyPriority(property)
728 + value:
729 + el.style.getPropertyValue(
730 + property
731 + ),
732 + priority:
733 + el.style.getPropertyPriority(
734 + property
735 + )
694 694   });
695 695   }
696 696  
697 - function restoreStyle(el,map,property){
739 + function restoreOriginal(el,map,property){
698 698   var original=map.get(el);
699 699  
700 700   if(original&&original.value){
... ... @@ -704,845 +704,770 @@
704 704   original.priority||""
705 705   );
706 706   }else{
707 - el.style.removeProperty(property);
749 + el.style.removeProperty(
750 + property
751 + );
708 708   }
709 709   }
710 710  
711 711   function resetRuntime(){
712 - managedHeight.forEach(function(el){
713 - restoreStyle(
756 + heightManaged.forEach(function(el){
757 + restoreOriginal(
714 714   el,
715 - originalHeight,
759 + originalMinHeight,
716 716   "min-height"
717 717   );
762 +
718 718   el.removeAttribute(
719 - "data-sn-master-equal-height"
764 + "data-sn-equal-height-managed"
720 720   );
721 721   });
722 722  
723 - managedMargin.forEach(function(el){
724 - restoreStyle(
768 + sectionManaged.forEach(function(el){
769 + restoreOriginal(
725 725   el,
726 - originalMargin,
771 + originalMarginTop,
727 727   "margin-top"
728 728   );
774 +
729 729   el.removeAttribute(
730 - "data-sn-master-first-row"
776 + "data-sn-first-section-aligned"
731 731   );
732 732   });
733 733  
734 - managedHeight.clear();
735 - managedMargin.clear();
736 - }
780 + contentManaged.forEach(function(el){
781 + restoreOriginal(
782 + el,
783 + originalMarginTop,
784 + "margin-top"
785 + );
737 737  
738 - function themeFor(text){
739 - var value=norm(text);
787 + el.removeAttribute(
788 + "data-sn-first-content-aligned"
789 + );
790 + });
740 740  
741 - for(var i=0;i<THEMES.length;i++){
742 - for(var j=0;j<THEMES[i].labels.length;j++){
743 - var label=THEMES[i].labels[j];
744 -
745 - if(
746 - value===label||
747 - value.indexOf(label+" ")===0||
748 - value.indexOf(label+" -")===0||
749 - value.indexOf(label+" ·")===0
750 - ){
751 - return THEMES[i];
752 - }
753 - }
754 - }
755 -
756 - return null;
792 + heightManaged.clear();
793 + sectionManaged.clear();
794 + contentManaged.clear();
757 757   }
758 758  
759 - /* =======================================================
760 - PLACEHOLDER BADGE
761 - ======================================================= */
797 + /* ---------- Card detection ---------- */
762 762  
763 - function applyPlaceholderBadge(){
764 - if(!PLACEHOLDER)return;
799 + function namedLikeBox(el){
800 + var c=
801 + typeof el.className==="string"
802 + ? el.className
803 + : "";
765 765  
805 + return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c);
806 + }
807 +
808 + function boxLike(el){
766 766   if(
767 - document.querySelector(
768 - ".sn-coming-soon-badge"
769 - )
810 + !visible(el,MIN_W,MIN_H)||
811 + excluded(el)
770 770   ){
771 - return;
813 + return false;
772 772   }
773 773  
774 - var title=
775 - document.querySelector(
776 - "#document-title"
777 - )||
778 - document.querySelector(
779 - "h1"
780 - );
816 + var s=getComputedStyle(el);
817 + var r=el.getBoundingClientRect();
781 781  
782 - if(!title)return;
819 + var border=
820 + num(s.borderTopWidth)+
821 + num(s.borderRightWidth)+
822 + num(s.borderBottomWidth)+
823 + num(s.borderLeftWidth);
783 783  
784 - var badge=
785 - document.createElement(
786 - "span"
787 - );
788 -
789 - badge.className=
790 - "sn-coming-soon-badge";
791 -
792 - badge.textContent=
793 - PLACEHOLDER_LABEL;
794 -
795 - badge.setAttribute(
796 - "aria-label",
797 - PLACEHOLDER_LABEL
825 + var radius=Math.max(
826 + num(s.borderTopLeftRadius),
827 + num(s.borderTopRightRadius),
828 + num(s.borderBottomLeftRadius),
829 + num(s.borderBottomRightRadius)
798 798   );
799 799  
800 - title.appendChild(
801 - badge
802 - );
803 - }
832 + var bg=
833 + s.backgroundColor&&
834 + s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
835 + s.backgroundColor!=="transparent";
804 804  
805 - /* =======================================================
806 - DETAIL PAGE OWN-ACCENT PROPAGATION
807 - ======================================================= */
837 + var shadow=
838 + s.boxShadow&&
839 + s.boxShadow!=="none";
808 808  
809 - function parseRGB(value){
810 - var match=String(value||"").match(
811 - /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
841 + return (
842 + namedLikeBox(el)||
843 + border>=1||
844 + (bg&&radius>=3)||
845 + (shadow&&r.width>=180)
812 812   );
813 -
814 - if(!match)return null;
815 -
816 - return [
817 - Number(match[1]),
818 - Number(match[2]),
819 - Number(match[3])
820 - ];
821 821   }
822 822  
823 - function distance(a,b){
824 - return Math.sqrt(
825 - Math.pow(a[0]-b[0],2)+
826 - Math.pow(a[1]-b[1],2)+
827 - Math.pow(a[2]-b[2],2)
828 - );
829 - }
849 + function pickTarget(child){
850 + if(!visible(child,MIN_W,MIN_H))return null;
830 830  
831 - function paletteMatch(cssColor){
832 - var rgb=parseRGB(cssColor);
852 + if(boxLike(child))return child;
833 833  
834 - if(!rgb)return null;
854 + var cr=child.getBoundingClientRect();
855 + var q=[];
835 835  
836 - var palette=[
837 - {hex:"#21b6d7",rgb:[33,182,215]},
838 - {hex:"#e94b13",rgb:[233,75,19]},
839 - {hex:"#f0aa00",rgb:[240,170,0]},
840 - {hex:"#38b76a",rgb:[56,183,106]}
841 - ];
857 + Array.from(child.children||[]).forEach(function(el){
858 + q.push({el:el,depth:1});
859 + });
842 842  
843 843   var best=null;
844 - var bestDistance=Infinity;
862 + var bestScore=-Infinity;
845 845  
846 - palette.forEach(function(item){
847 - var d=distance(rgb,item.rgb);
864 + while(q.length){
865 + var item=q.shift();
866 + var el=item.el;
848 848  
849 - if(d<bestDistance){
850 - best=item;
851 - bestDistance=d;
852 - }
853 - });
868 + if(!visible(el,MIN_W,MIN_H))continue;
854 854  
855 - return bestDistance<=30
856 - ?best
857 - :null;
858 - }
870 + var r=el.getBoundingClientRect();
859 859  
860 - function propagateDetailAccents(){
861 - if(PAGE_KIND!=="detail")return;
862 -
863 - Array.from(
864 - root.querySelectorAll(
865 - ".arsn-call,.dmp-call,.ido-call,.pp-call,"+
866 - ".arsn-source,.dmp-source,.ido-source,.pp-source"
867 - )
868 - ).forEach(function(el){
869 - if(!visible(el))return;
870 -
871 - var style=getComputedStyle(el);
872 -
873 873   if(
874 - num(style.borderTopWidth)>=2
873 + r.width>=cr.width*.68&&
874 + boxLike(el)
875 875   ){
876 - var match=
877 - paletteMatch(
878 - style.borderTopColor
876 + var widthFit=
877 + 1-Math.min(
878 + 1,
879 + Math.abs(cr.width-r.width)/
880 + Math.max(1,cr.width)
879 879   );
880 880  
881 - if(match){
882 - el.style.setProperty(
883 - "border-left",
884 - "4px solid "+match.hex,
885 - "important"
883 + var topFit=
884 + 1-Math.min(
885 + 1,
886 + Math.abs(cr.top-r.top)/100
886 886   );
888 +
889 + var score=
890 + widthFit*6+
891 + topFit*3+
892 + Math.min(r.height,900)/450+
893 + Math.min(r.width*r.height,900000)/900000;
894 +
895 + if(score>bestScore){
896 + best=el;
897 + bestScore=score;
887 887   }
888 888   }
889 - });
890 890  
891 - // Warning families: explicit safety override.
892 - Array.from(
893 - root.querySelectorAll(
894 - ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+
895 - ".warn,.warning,.warningmessage,.errormessage"
896 - )
897 - ).forEach(function(el){
898 - if(!visible(el))return;
901 + if(item.depth<SEARCH_DEPTH){
902 + Array.from(el.children||[]).forEach(function(next){
903 + q.push({
904 + el:next,
905 + depth:item.depth+1
906 + });
907 + });
908 + }
909 + }
899 899  
900 - el.style.setProperty(
901 - "border-left",
902 - "4px solid #e94b13",
903 - "important"
904 - );
905 - });
911 + return best;
912 + }
906 906  
907 - // Info families: explicit orientation override.
908 - Array.from(
909 - root.querySelectorAll(
910 - ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage"
911 - )
912 - ).forEach(function(el){
913 - if(!visible(el))return;
914 + function groupRows(entries){
915 + var groups=[];
914 914  
915 - el.style.setProperty(
916 - "border-left",
917 - "4px solid #21b6d7",
918 - "important"
919 - );
920 - });
921 - }
917 + entries
918 + .slice()
919 + .sort(function(a,b){
920 + return (
921 + a.rect.top-b.rect.top||
922 + a.rect.left-b.rect.left
923 + );
924 + })
925 + .forEach(function(entry){
926 + var group=null;
922 922  
923 - /* =======================================================
924 - OVERVIEW SEMANTIC THEME PALETTE
925 - ======================================================= */
928 + for(var i=0;i<groups.length;i++){
929 + if(
930 + Math.abs(
931 + groups[i].top-
932 + entry.rect.top
933 + )<=ROW_TOLERANCE
934 + ){
935 + group=groups[i];
936 + break;
937 + }
938 + }
926 926  
927 - function smallestThemeHeaders(){
928 - return Array.from(
929 - root.querySelectorAll(
930 - "div,span,p,strong,h3,h4,h5,h6"
931 - )
932 - ).filter(function(el){
933 - if(!visible(el))return false;
934 - if(!themeFor(el.textContent))return false;
940 + if(!group){
941 + group={
942 + top:entry.rect.top,
943 + entries:[]
944 + };
945 + groups.push(group);
946 + }
935 935  
936 - return !Array.from(
937 - el.children||[]
938 - ).some(function(child){
939 - return !!themeFor(
940 - child.textContent
941 - );
948 + group.entries.push(entry);
942 942   });
943 - });
950 +
951 + return groups;
944 944   }
945 945  
946 - function findOverviewCard(header){
947 - var node=header.parentElement;
948 - var candidates=[];
954 + function validRow(group){
955 + if(group.entries.length<2)return false;
949 949  
950 - while(node&&node!==root){
951 - var rect=node.getBoundingClientRect();
952 - var style=getComputedStyle(node);
957 + var lefts=
958 + group.entries
959 + .map(function(e){return e.rect.left;})
960 + .sort(function(a,b){return a-b;});
953 953  
954 - var border=
955 - num(style.borderTopWidth)+
956 - num(style.borderRightWidth)+
957 - num(style.borderBottomWidth)+
958 - num(style.borderLeftWidth);
962 + if(
963 + lefts[lefts.length-1]-
964 + lefts[0]<
965 + 80
966 + ){
967 + return false;
968 + }
959 959  
960 - if(
961 - rect.width>=220&&
962 - rect.width<=800&&
963 - rect.height>=120&&
964 - border>=1
965 - ){
966 - candidates.push(node);
967 - }
970 + var widths=
971 + group.entries
972 + .map(function(e){return e.rect.width;})
973 + .filter(function(w){return w>0;});
968 968  
969 - node=node.parentElement;
970 - }
975 + if(widths.length<2)return false;
971 971  
972 - if(!candidates.length)return null;
977 + var minW=
978 + Math.min.apply(Math,widths);
973 973  
974 - candidates.sort(function(a,b){
975 - return (
976 - b.getBoundingClientRect().height-
977 - a.getBoundingClientRect().height
980 + var maxW=
981 + Math.max.apply(Math,widths);
982 +
983 + return (
984 + maxW/
985 + Math.max(1,minW)<=
986 + 1.9
987 + );
988 + }
989 +
990 + /* ---------- Known ARSN first section bars ---------- */
991 +
992 + function knownBar(el){
993 + var text=
994 + normalizeText(
995 + el.textContent
978 978   );
979 - });
980 980  
981 - return candidates[0];
998 + return (
999 + text==="HIER STARTEN"||
1000 + text==="ORGANISIEREN & DOKUMENTIEREN"||
1001 + text==="ENTSCHEIDEN"||
1002 + text==="START HERE"||
1003 + text==="GET STARTED"||
1004 + text==="ORGANISE & DOCUMENT"||
1005 + text==="ORGANIZE & DOCUMENT"||
1006 + text==="DECIDE"
1007 + );
982 982   }
983 983  
984 - function rowCandidates(link,card){
985 - var result=[];
1010 + function findKnownBar(card){
986 986   var cardRect=
987 987   card.getBoundingClientRect();
988 988  
989 - var node=link;
1014 + var rows=
1015 + Array.from(
1016 + card.querySelectorAll(
1017 + "div,p,span,strong,h3,h4,h5,h6"
1018 + )
1019 + )
1020 + .filter(function(el){
1021 + if(!visible(el,20,6))return false;
1022 + if(!knownBar(el))return false;
990 990  
991 - while(node&&node!==card){
992 - if(visible(node)){
993 - var rect=
994 - node.getBoundingClientRect();
1024 + var r=el.getBoundingClientRect();
995 995  
996 - if(
997 - rect.height<=105&&
998 - rect.width>=
999 - cardRect.width*.50&&
1000 - rect.width<=
1001 - cardRect.width*1.03
1002 - ){
1003 - result.push(node);
1004 - }
1005 - }
1026 + var rel=
1027 + r.top-
1028 + cardRect.top;
1006 1006  
1007 - node=node.parentElement;
1008 - }
1009 -
1010 - return result;
1011 - }
1012 -
1013 - function chooseOuterRow(
1014 - candidates,
1015 - link
1016 - ){
1017 - if(!candidates.length){
1018 - return link;
1019 - }
1020 -
1021 - var bordered=
1022 - candidates.filter(function(el){
1023 1023   return (
1024 - num(
1025 - getComputedStyle(el)
1026 - .borderLeftWidth
1027 - )>=1
1031 + rel>=35&&
1032 + rel<=
1033 + cardRect.height*.75
1028 1028   );
1035 + })
1036 + .sort(function(a,b){
1037 + return (
1038 + a.getBoundingClientRect().top-
1039 + b.getBoundingClientRect().top
1040 + );
1029 1029   });
1030 1030  
1031 - var pool=
1032 - bordered.length
1033 - ?bordered
1034 - :candidates;
1043 + return rows[0]||null;
1044 + }
1035 1035  
1036 - pool.sort(function(a,b){
1037 - var ar=
1038 - a.getBoundingClientRect();
1046 + function alignKnownBars(cards){
1047 + var rows=
1048 + cards.map(function(card){
1049 + var bar=
1050 + findKnownBar(card);
1039 1039  
1040 - var br=
1041 - b.getBoundingClientRect();
1052 + if(!bar)return null;
1042 1042  
1043 - return (
1044 - ar.left-br.left||
1045 - br.width-ar.width
1046 - );
1047 - });
1054 + var cr=
1055 + card.getBoundingClientRect();
1048 1048  
1049 - return pool[0]||link;
1050 - }
1057 + var br=
1058 + bar.getBoundingClientRect();
1051 1051  
1052 - function applyOverviewPalette(){
1053 - if(PAGE_KIND!=="overview"){
1054 - return [];
1060 + return {
1061 + bar:bar,
1062 + relativeTop:
1063 + br.top-
1064 + cr.top
1065 + };
1066 + });
1067 +
1068 + if(
1069 + rows.some(function(row){
1070 + return !row;
1071 + })
1072 + ){
1073 + return false;
1055 1055   }
1056 1056  
1057 - var headers=
1058 - smallestThemeHeaders()
1059 - .map(function(el){
1060 - return {
1061 - el:el,
1062 - theme:
1063 - themeFor(
1064 - el.textContent
1065 - ),
1066 - card:
1067 - findOverviewCard(
1068 - el
1069 - )
1070 - };
1076 + var target=
1077 + Math.max.apply(
1078 + Math,
1079 + rows.map(function(row){
1080 + return row.relativeTop;
1071 1071   })
1072 - .filter(function(row){
1073 - return !!row.card;
1074 - });
1082 + );
1075 1075  
1076 - var unique=[];
1077 - var seenHeaders=new Set();
1084 + rows.forEach(function(row){
1085 + var delta=
1086 + target-
1087 + row.relativeTop;
1078 1078  
1079 - headers.forEach(function(row){
1080 - var key=
1081 - row.theme.name+
1082 - "|"+
1083 - Math.round(
1084 - row.card
1085 - .getBoundingClientRect()
1086 - .left
1087 - )+
1088 - "|"+
1089 - Math.round(
1090 - row.el
1091 - .getBoundingClientRect()
1092 - .top
1093 - );
1089 + if(delta<=1)return;
1094 1094  
1095 - if(!seenHeaders.has(key)){
1096 - seenHeaders.add(key);
1097 - unique.push(row);
1098 - }
1099 - });
1091 + saveOriginal(
1092 + row.bar,
1093 + originalMarginTop,
1094 + "margin-top"
1095 + );
1100 1100  
1101 - unique.forEach(function(row){
1102 - var headerRect=
1103 - row.el
1104 - .getBoundingClientRect();
1097 + var current=
1098 + num(
1099 + getComputedStyle(
1100 + row.bar
1101 + ).marginTop
1102 + );
1105 1105  
1106 - row.el.style.setProperty(
1107 - "background",
1108 - row.theme.bg,
1109 - "important"
1104 + row.bar.style.setProperty(
1105 + "margin-top",
1106 + (
1107 + current+
1108 + delta
1109 + )+"px"
1110 1110   );
1111 1111  
1112 - row.el.style.setProperty(
1113 - "color",
1114 - row.theme.text,
1115 - "important"
1112 + row.bar.setAttribute(
1113 + "data-sn-first-section-aligned",
1114 + "7"
1116 1116   );
1117 1117  
1118 - row.el.style.setProperty(
1119 - "text-align",
1120 - "left",
1121 - "important"
1117 + sectionManaged.add(
1118 + row.bar
1122 1122   );
1120 + });
1123 1123  
1124 - row.el.style.setProperty(
1125 - "word-spacing",
1126 - "normal",
1127 - "important"
1128 - );
1122 + return true;
1123 + }
1129 1129  
1130 - var later=
1131 - unique
1132 - .filter(function(other){
1133 - return (
1134 - other.card===row.card&&
1135 - other.el
1136 - .getBoundingClientRect()
1137 - .top>
1138 - headerRect.top+2
1139 - );
1140 - })
1141 - .sort(function(a,b){
1142 - return (
1143 - a.el
1144 - .getBoundingClientRect()
1145 - .top-
1146 - b.el
1147 - .getBoundingClientRect()
1148 - .top
1149 - );
1150 - });
1125 + /* ---------- Generic first content after heading ---------- */
1151 1151  
1152 - var stopTop=
1153 - later.length
1154 - ?later[0].el
1155 - .getBoundingClientRect()
1156 - .top
1157 - :Infinity;
1127 + function heading(card){
1128 + var cr=
1129 + card.getBoundingClientRect();
1158 1158  
1131 + var rows=
1159 1159   Array.from(
1160 - row.card.querySelectorAll("a")
1161 - ).forEach(function(link){
1162 - if(!visible(link))return;
1133 + card.querySelectorAll(
1134 + "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]"
1135 + )
1136 + )
1137 + .filter(function(el){
1138 + if(!visible(el,20,8))return false;
1163 1163  
1164 - var rect=
1165 - link.getBoundingClientRect();
1140 + var r=el.getBoundingClientRect();
1166 1166  
1167 - if(
1168 - rect.top<=
1169 - headerRect.bottom-2||
1170 - rect.top>=
1171 - stopTop-2
1172 - ){
1173 - return;
1174 - }
1142 + var rel=
1143 + r.top-
1144 + cr.top;
1175 1175  
1176 - var candidates=
1177 - rowCandidates(
1178 - link,
1179 - row.card
1180 - );
1181 -
1182 - var target=
1183 - chooseOuterRow(
1184 - candidates,
1185 - link
1186 - );
1187 -
1188 - candidates.forEach(function(el){
1189 - el.style.setProperty(
1190 - "border-left",
1191 - "0 solid transparent",
1192 - "important"
1193 - );
1194 - });
1195 -
1196 - target.style.setProperty(
1197 - "border-left",
1198 - "3px solid "+
1199 - row.theme.accent,
1200 - "important"
1146 + return (
1147 + rel>=0&&
1148 + rel<=
1149 + Math.min(
1150 + 160,
1151 + cr.height*.45
1152 + )
1201 1201   );
1202 -
1203 - target.style.setProperty(
1204 - "box-sizing",
1205 - "border-box",
1206 - "important"
1154 + })
1155 + .sort(function(a,b){
1156 + return (
1157 + a.getBoundingClientRect().top-
1158 + b.getBoundingClientRect().top
1207 1207   );
1208 1208   });
1209 - });
1210 1210  
1211 - return unique;
1162 + return rows[0]||null;
1212 1212   }
1213 1213  
1214 - /* =======================================================
1215 - OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1216 - ======================================================= */
1165 + function firstContent(card,h){
1166 + if(!h)return null;
1217 1217  
1218 - function alignOverviewCards(headers){
1219 - if(
1220 - PAGE_KIND!=="overview"||
1221 - window.innerWidth<=MOBILE_MAX
1222 - ){
1223 - return;
1224 - }
1168 + var cr=
1169 + card.getBoundingClientRect();
1225 1225  
1226 - var cards=[];
1227 - var seen=new Set();
1171 + var hr=
1172 + h.getBoundingClientRect();
1228 1228  
1229 - headers.forEach(function(row){
1230 - if(!seen.has(row.card)){
1231 - seen.add(row.card);
1232 - cards.push(row.card);
1233 - }
1234 - });
1174 + var rows=
1175 + Array.from(
1176 + card.querySelectorAll(
1177 + "p,div,ul,ol,dl,blockquote"
1178 + )
1179 + )
1180 + .filter(function(el){
1181 + if(
1182 + el===h||
1183 + h.contains(el)||
1184 + el.contains(h)
1185 + ){
1186 + return false;
1187 + }
1235 1235  
1236 - if(cards.length<2){
1237 - return;
1238 - }
1189 + if(!visible(el,30,8))return false;
1239 1239  
1240 - // Group cards by actual top position.
1241 - var groups=[];
1191 + var text=
1192 + String(el.textContent||"")
1193 + .replace(/\s+/g," ")
1194 + .trim();
1242 1242  
1243 - cards.forEach(function(card){
1244 - var top=
1245 - card.getBoundingClientRect().top;
1196 + if(text.length<3)return false;
1246 1246  
1247 - var group=null;
1198 + var r=el.getBoundingClientRect();
1248 1248  
1249 - for(var i=0;i<groups.length;i++){
1250 1250   if(
1251 - Math.abs(
1252 - groups[i].top-top
1253 - )<=ROW_TOLERANCE
1201 + r.top<
1202 + hr.bottom-1
1254 1254   ){
1255 - group=groups[i];
1256 - break;
1204 + return false;
1257 1257   }
1258 - }
1259 1259  
1260 - if(!group){
1261 - group={
1262 - top:top,
1263 - cards:[]
1264 - };
1265 - groups.push(group);
1266 - }
1207 + if(
1208 + r.top-cr.top>
1209 + Math.min(
1210 + 280,
1211 + cr.height*.65
1212 + )
1213 + ){
1214 + return false;
1215 + }
1267 1267  
1268 - group.cards.push(card);
1269 - });
1217 + if(
1218 + r.height>
1219 + cr.height*.58
1220 + ){
1221 + return false;
1222 + }
1270 1270  
1271 - groups.forEach(function(group){
1272 - if(group.cards.length<2){
1273 - return;
1274 - }
1224 + return true;
1225 + })
1226 + .sort(function(a,b){
1227 + var ar=
1228 + a.getBoundingClientRect();
1275 1275  
1276 - var firstHeaders=
1277 - group.cards.map(function(card){
1278 - var candidates=
1279 - headers
1280 - .filter(function(row){
1281 - return row.card===card;
1282 - })
1283 - .sort(function(a,b){
1284 - return (
1285 - a.el
1286 - .getBoundingClientRect()
1287 - .top-
1288 - b.el
1289 - .getBoundingClientRect()
1290 - .top
1291 - );
1292 - });
1230 + var br=
1231 + b.getBoundingClientRect();
1293 1293  
1294 - return candidates.length
1295 - ?candidates[0]
1296 - :null;
1297 - });
1233 + return (
1234 + ar.top-br.top||
1235 + ar.height-br.height
1236 + );
1237 + });
1298 1298  
1299 - if(
1300 - !firstHeaders.some(function(row){
1301 - return !row;
1302 - })
1303 - ){
1304 - var targetTop=
1305 - Math.max.apply(
1306 - Math,
1307 - firstHeaders.map(function(row){
1308 - return (
1309 - row.el
1310 - .getBoundingClientRect()
1311 - .top-
1312 - row.card
1313 - .getBoundingClientRect()
1314 - .top
1315 - );
1316 - })
1317 - );
1239 + return rows[0]||null;
1240 + }
1318 1318  
1319 - firstHeaders.forEach(function(row){
1320 - var relativeTop=
1321 - row.el
1322 - .getBoundingClientRect()
1323 - .top-
1324 - row.card
1325 - .getBoundingClientRect()
1326 - .top;
1242 + function alignGeneric(cards){
1243 + var rows=
1244 + cards.map(function(card){
1245 + var h=
1246 + heading(card);
1327 1327  
1328 - var delta=
1329 - targetTop-relativeTop;
1248 + var c=
1249 + firstContent(
1250 + card,
1251 + h
1252 + );
1330 1330  
1331 - if(delta>1){
1332 - saveStyle(
1333 - row.el,
1334 - originalMargin,
1335 - "margin-top"
1336 - );
1254 + if(!h||!c)return null;
1337 1337  
1338 - var current=
1339 - num(
1340 - getComputedStyle(
1341 - row.el
1342 - ).marginTop
1343 - );
1256 + var cr=
1257 + card.getBoundingClientRect();
1344 1344  
1345 - row.el.style.setProperty(
1346 - "margin-top",
1347 - (
1348 - current+delta
1349 - )+"px"
1350 - );
1259 + var rr=
1260 + c.getBoundingClientRect();
1351 1351  
1352 - row.el.setAttribute(
1353 - "data-sn-master-first-row",
1354 - "1"
1355 - );
1262 + return {
1263 + content:c,
1264 + relativeTop:
1265 + rr.top-cr.top
1266 + };
1267 + });
1356 1356  
1357 - managedMargin.add(
1358 - row.el
1359 - );
1360 - }
1361 - });
1362 - }
1269 + if(
1270 + rows.some(function(row){
1271 + return !row;
1272 + })
1273 + ){
1274 + return false;
1275 + }
1363 1363  
1364 - var maxHeight=0;
1277 + var target=
1278 + Math.max.apply(
1279 + Math,
1280 + rows.map(function(row){
1281 + return row.relativeTop;
1282 + })
1283 + );
1365 1365  
1366 - group.cards.forEach(function(card){
1367 - maxHeight=
1368 - Math.max(
1369 - maxHeight,
1370 - card
1371 - .getBoundingClientRect()
1372 - .height
1373 - );
1374 - });
1285 + rows.forEach(function(row){
1286 + var delta=
1287 + target-
1288 + row.relativeTop;
1375 1375  
1376 - maxHeight=
1377 - Math.ceil(maxHeight);
1290 + if(delta<=1)return;
1378 1378  
1379 - group.cards.forEach(function(card){
1380 - saveStyle(
1381 - card,
1382 - originalHeight,
1383 - "min-height"
1384 - );
1292 + saveOriginal(
1293 + row.content,
1294 + originalMarginTop,
1295 + "margin-top"
1296 + );
1385 1385  
1386 - card.style.setProperty(
1387 - "min-height",
1388 - maxHeight+"px"
1298 + var current=
1299 + num(
1300 + getComputedStyle(
1301 + row.content
1302 + ).marginTop
1389 1389   );
1390 1390  
1391 - card.setAttribute(
1392 - "data-sn-master-equal-height",
1393 - "1"
1394 - );
1305 + row.content.style.setProperty(
1306 + "margin-top",
1307 + (
1308 + current+
1309 + delta
1310 + )+"px"
1311 + );
1395 1395  
1396 - managedHeight.add(
1397 - card
1398 - );
1399 - });
1313 + row.content.setAttribute(
1314 + "data-sn-first-content-aligned",
1315 + "7"
1316 + );
1317 +
1318 + contentManaged.add(
1319 + row.content
1320 + );
1400 1400   });
1322 +
1323 + return true;
1401 1401   }
1402 1402  
1403 - /* =======================================================
1404 - DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY
1405 - ======================================================= */
1326 + function applyRow(group){
1327 + if(!validRow(group))return false;
1406 1406  
1407 - function equaliseDetailGrids(){
1329 + var cards=[];
1330 + var seen=new Set();
1331 +
1332 + group.entries.forEach(function(entry){
1333 + if(!seen.has(entry.target)){
1334 + seen.add(entry.target);
1335 + cards.push(entry.target);
1336 + }
1337 + });
1338 +
1339 + if(cards.length<2)return false;
1340 +
1408 1408   if(
1409 - PAGE_KIND!=="detail"||
1410 - window.innerWidth<=MOBILE_MAX
1342 + !alignKnownBars(cards)
1411 1411   ){
1412 - return;
1344 + alignGeneric(cards);
1413 1413   }
1414 1414  
1415 - var selectors=[
1416 - ".arsn-grid",
1417 - ".arsn-grid-2",
1418 - ".arsn-grid-3",
1419 - ".dmp-grid",
1420 - ".ido-grid",
1421 - ".pp-grid"
1422 - ];
1347 + var maxHeight=0;
1423 1423  
1424 - selectors.forEach(function(selector){
1425 - Array.from(
1426 - root.querySelectorAll(selector)
1427 - ).forEach(function(grid){
1428 - var children=
1429 - Array.from(
1430 - grid.children||[]
1431 - ).filter(visible);
1349 + cards.forEach(function(card){
1350 + maxHeight=
1351 + Math.max(
1352 + maxHeight,
1353 + card.getBoundingClientRect().height
1354 + );
1355 + });
1432 1432  
1433 - if(children.length<2){
1434 - return;
1435 - }
1357 + maxHeight=
1358 + Math.ceil(
1359 + maxHeight
1360 + );
1436 1436  
1437 - var groups=[];
1362 + if(maxHeight<MIN_H)return false;
1438 1438  
1439 - children.forEach(function(child){
1440 - var top=
1441 - child
1442 - .getBoundingClientRect()
1443 - .top;
1364 + cards.forEach(function(card){
1365 + saveOriginal(
1366 + card,
1367 + originalMinHeight,
1368 + "min-height"
1369 + );
1444 1444  
1445 - var group=null;
1371 + card.style.setProperty(
1372 + "min-height",
1373 + maxHeight+"px"
1374 + );
1446 1446  
1447 - for(var i=0;i<groups.length;i++){
1448 - if(
1449 - Math.abs(
1450 - groups[i].top-top
1451 - )<=ROW_TOLERANCE
1452 - ){
1453 - group=groups[i];
1454 - break;
1455 - }
1456 - }
1376 + card.setAttribute(
1377 + "data-sn-equal-height-managed",
1378 + "7"
1379 + );
1457 1457  
1458 - if(!group){
1459 - group={
1460 - top:top,
1461 - items:[]
1462 - };
1463 - groups.push(group);
1464 - }
1381 + heightManaged.add(card);
1382 + });
1465 1465  
1466 - group.items.push(child);
1467 - });
1384 + return true;
1385 + }
1468 1468  
1469 - groups.forEach(function(group){
1470 - if(group.items.length<2){
1471 - return;
1472 - }
1387 + function calculate(force){
1388 + if(applying)return;
1473 1473  
1474 - var maxHeight=0;
1390 + var width=
1391 + Math.round(
1392 + window.innerWidth
1393 + );
1475 1475  
1476 - group.items.forEach(function(item){
1477 - maxHeight=
1478 - Math.max(
1479 - maxHeight,
1480 - item
1481 - .getBoundingClientRect()
1482 - .height
1483 - );
1484 - });
1395 + var meaningful=
1396 + lastWidth<0||
1397 + Math.abs(
1398 + width-
1399 + lastWidth
1400 + )>=
1401 + MIN_WIDTH_CHANGE;
1485 1485  
1486 - maxHeight=
1487 - Math.ceil(maxHeight);
1403 + if(
1404 + hasApplied&&
1405 + !force&&
1406 + !meaningful
1407 + ){
1408 + return;
1409 + }
1488 1488  
1489 - group.items.forEach(function(item){
1490 - saveStyle(
1491 - item,
1492 - originalHeight,
1493 - "min-height"
1494 - );
1411 + applying=true;
1495 1495  
1496 - item.style.setProperty(
1497 - "min-height",
1498 - maxHeight+"px"
1499 - );
1413 + try{
1414 + harmoniseCustomCallouts();
1500 1500  
1501 - item.setAttribute(
1502 - "data-sn-master-equal-height",
1503 - "1"
1504 - );
1416 + if(width<=MOBILE_MAX){
1417 + if(hasApplied){
1418 + resetRuntime();
1419 + }
1505 1505  
1506 - managedHeight.add(item);
1507 - });
1421 + hasApplied=false;
1422 + lastWidth=width;
1423 + return;
1424 + }
1425 +
1426 + if(hasApplied){
1427 + resetRuntime();
1428 + }
1429 +
1430 + var parents=
1431 + Array.from(
1432 + root.querySelectorAll("*")
1433 + )
1434 + .filter(function(parent){
1435 + return (
1436 + visible(
1437 + parent,
1438 + MIN_W,
1439 + MIN_H
1440 + )&&
1441 + parent.children&&
1442 + parent.children.length>=2&&
1443 + parent.children.length<=
1444 + MAX_PARENT_CHILDREN
1445 + );
1508 1508   });
1509 - });
1510 - });
1511 - }
1512 1512  
1513 - /* =======================================================
1514 - RUN / RESPONSIVE SCHEDULING
1515 - ======================================================= */
1448 + var touched=
1449 + new Set();
1516 1516  
1517 - function run(){
1518 - if(running)return;
1451 + parents.forEach(function(parent){
1452 + var entries=[];
1519 1519  
1520 - running=true;
1454 + Array.from(
1455 + parent.children
1456 + ).forEach(function(child){
1457 + if(
1458 + !visible(
1459 + child,
1460 + MIN_W,
1461 + MIN_H
1462 + )
1463 + ){
1464 + return;
1465 + }
1521 1521  
1522 - try{
1523 - resetRuntime();
1524 - applyPlaceholderBadge();
1525 - propagateDetailAccents();
1467 + var target=
1468 + pickTarget(child);
1526 1526  
1527 - var headers=
1528 - applyOverviewPalette();
1470 + if(!target)return;
1529 1529  
1530 - if(
1531 - window.innerWidth>
1532 - MOBILE_MAX
1533 - ){
1534 - alignOverviewCards(
1535 - headers
1536 - );
1472 + entries.push({
1473 + target:target,
1474 + rect:
1475 + target.getBoundingClientRect()
1476 + });
1477 + });
1537 1537  
1538 - equaliseDetailGrids();
1539 - }
1479 + groupRows(
1480 + entries
1481 + ).forEach(function(group){
1482 + if(!validRow(group))return;
1483 +
1484 + var targets=
1485 + group.entries.map(function(entry){
1486 + return entry.target;
1487 + });
1488 +
1489 + if(
1490 + !targets.some(function(el){
1491 + return !touched.has(el);
1492 + })
1493 + ){
1494 + return;
1495 + }
1496 +
1497 + if(applyRow(group)){
1498 + targets.forEach(function(el){
1499 + touched.add(el);
1500 + });
1501 + }
1502 + });
1503 + });
1504 +
1505 + lastWidth=width;
1506 + hasApplied=true;
1540 1540   }finally{
1541 - running=false;
1508 + applying=false;
1542 1542   }
1543 1543   }
1544 1544  
1545 - function onResize(){
1512 + function resize(){
1546 1546   if(resizeTimer){
1547 1547   clearTimeout(
1548 1548   resizeTimer
... ... @@ -1553,40 +1553,19 @@
1553 1553   setTimeout(
1554 1554   function(){
1555 1555   resizeTimer=0;
1556 - run();
1523 + calculate(false);
1557 1557   },
1558 1558   RESIZE_DEBOUNCE
1559 1559   );
1560 1560   }
1561 1561  
1562 - async function waitForReady(){
1563 - if(
1564 - document.readyState!=="complete"
1565 - ){
1566 - await new Promise(function(resolve){
1567 - window.addEventListener(
1568 - "load",
1569 - resolve,
1570 - {once:true}
1571 - );
1572 - });
1573 - }
1574 -
1575 - if(
1576 - document.fonts&&
1577 - document.fonts.ready
1578 - ){
1579 - try{
1580 - await document.fonts.ready;
1581 - }catch(error){}
1582 - }
1583 -
1529 + function waitImages(){
1584 1584   var images=
1585 1585   Array.from(
1586 1586   root.querySelectorAll("img")
1587 1587   );
1588 1588  
1589 - await Promise.all(
1535 + return Promise.all(
1590 1590   images.map(function(img){
1591 1591   if(img.complete){
1592 1592   return Promise.resolve();
... ... @@ -1611,20 +1611,46 @@
1611 1611   });
1612 1612   })
1613 1613   );
1560 + }
1614 1614  
1615 - run();
1562 + async function initial(){
1563 + if(
1564 + document.readyState!==
1565 + "complete"
1566 + ){
1567 + await new Promise(function(resolve){
1568 + addEventListener(
1569 + "load",
1570 + resolve,
1571 + {once:true}
1572 + );
1573 + });
1574 + }
1575 +
1576 + if(
1577 + document.fonts&&
1578 + document.fonts.ready
1579 + ){
1580 + try{
1581 + await document.fonts.ready;
1582 + }catch(error){}
1583 + }
1584 +
1585 + await waitImages();
1586 +
1587 + // Exactly one initial layout calculation.
1588 + calculate(true);
1616 1616   }
1617 1617  
1618 - window.addEventListener(
1591 + addEventListener(
1619 1619   "resize",
1620 - onResize,
1593 + resize,
1621 1621   {passive:true}
1622 1622   );
1623 1623  
1624 - waitForReady();
1597 + initial();
1625 1625  })();
1626 1626  </script>
1627 1627  
1628 -<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
1629 -{{/html}}
1630 -
1601 +<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
1602 +{{/html}}\n