Changes for page Service Navigator

Last modified by Veronika Kocher on Thursday, 03 Sep 2026 14:15

From version 22.15
edited by Veronika Kocher
on Thursday, 03 Sep 2026 10:09
Change comment: There is no comment for this version
To version 22.16
edited by Veronika Kocher
on Thursday, 03 Sep 2026 13:04
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -285,12 +285,13 @@
285 285  </div>
286 286  {{/html}}
287 287  
288 -\n\n
289 -\n\n{{html clean="false"}}
290 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_START -->
288 +{{html clean="false"}}
289 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_START -->
291 291  
292 -<style data-sn-horizontal-box-harmonizer="7">
293 -/* ---------- Typography: never justify headings ---------- */
291 +<style data-sn-service-navigator-master="1">
292 +/* =========================================================
293 + MASTER TYPOGRAPHY
294 + ========================================================= */
294 294  #xwikicontent h1,
295 295  #xwikicontent h2,
296 296  #xwikicontent h3,
... ... @@ -312,88 +312,73 @@
312 312   word-spacing:normal!important;
313 313  }
314 314  
315 -/* ---------- Native XWiki semantic callouts ---------- */
316 -#xwikicontent .box.infomessage,
317 -#xwikicontent .infomessage,
318 -#xwikicontent .box.warningmessage,
319 -#xwikicontent .warningmessage,
320 -#xwikicontent .box.successmessage,
321 -#xwikicontent .successmessage,
322 -#xwikicontent .box.errormessage,
323 -#xwikicontent .errormessage,
324 -#xwikicontent [data-sn-callout-harmonized="1"]{
316 +/* =========================================================
317 + COMING SOON / IN VORBEREITUNG
318 + ========================================================= */
319 +.sn-coming-soon-badge{
320 + display:inline-block;
321 + vertical-align:middle;
322 + margin-left:10px;
323 + padding:4px 8px;
324 + border-radius:14px;
325 + border:1px solid #efd9cc;
326 + background:#fff4ee;
327 + color:#8a4d36;
328 + font-size:11px;
329 + font-weight:700;
330 + letter-spacing:.055em;
331 + line-height:1.2;
332 + white-space:nowrap;
333 +}
334 +
335 +/* =========================================================
336 + NATIVE / DETAIL CALLOUT GEOMETRY
337 + Preserve existing backgrounds.
338 + ========================================================= */
339 +#xwikicontent .arsn-info,
340 +#xwikicontent .dmp-info,
341 +#xwikicontent .ido-info,
342 +#xwikicontent .pp-info,
343 +#xwikicontent .infomessage{
325 325   box-sizing:border-box!important;
326 - border-radius:8px!important;
327 - border-top:1px solid rgba(0,0,0,.08)!important;
328 - border-right:1px solid rgba(0,0,0,.08)!important;
329 - border-bottom:1px solid rgba(0,0,0,.08)!important;
330 - border-left:4px solid var(--sn-callout-accent,#21b6d7)!important;
331 - padding:14px 16px!important;
345 + border-left:4px solid #21b6d7!important;
346 + border-radius:8px;
332 332   text-align:left!important;
333 - text-justify:auto!important;
334 334   word-spacing:normal!important;
335 - box-shadow:none!important;
336 336  }
337 337  
338 -#xwikicontent .box.infomessage,
339 -#xwikicontent .infomessage{
340 - --sn-callout-accent:#21b6d7;
341 - background:#eaf7fb!important;
342 -}
343 -
344 -#xwikicontent .box.warningmessage,
345 -#xwikicontent .warningmessage{
346 - --sn-callout-accent:#f0aa00;
347 - background:#fff8e7!important;
348 -}
349 -
350 -#xwikicontent .box.successmessage,
351 -#xwikicontent .successmessage{
352 - --sn-callout-accent:#38b76a;
353 - background:#edf9f1!important;
354 -}
355 -
356 -#xwikicontent .box.errormessage,
351 +#xwikicontent .arsn-warn,
352 +#xwikicontent .dmp-warn,
353 +#xwikicontent .ido-warn,
354 +#xwikicontent .pp-warn,
355 +#xwikicontent .warn,
356 +#xwikicontent .warning,
357 +#xwikicontent .warningmessage,
357 357  #xwikicontent .errormessage{
358 - --sn-callout-accent:#e94b13;
359 - background:#fff1ec!important;
359 + box-sizing:border-box!important;
360 + border-left:4px solid #e94b13!important;
361 + border-radius:8px;
362 + text-align:left!important;
363 + word-spacing:normal!important;
360 360  }
361 361  
362 -#xwikicontent [data-sn-callout-harmonized="1"] > :first-child,
363 -#xwikicontent .infomessage > :first-child,
364 -#xwikicontent .warningmessage > :first-child,
365 -#xwikicontent .successmessage > :first-child,
366 -#xwikicontent .errormessage > :first-child{
367 - margin-top:0!important;
368 -}
369 -
370 -#xwikicontent [data-sn-callout-harmonized="1"] > :last-child,
371 -#xwikicontent .infomessage > :last-child,
372 -#xwikicontent .warningmessage > :last-child,
373 -#xwikicontent .successmessage > :last-child,
374 -#xwikicontent .errormessage > :last-child{
375 - margin-bottom:0!important;
376 -}
377 -
378 -#xwikicontent [data-sn-equal-height-managed],
379 -#xwikicontent [data-sn-first-section-aligned],
380 -#xwikicontent [data-sn-first-content-aligned]{
366 +[data-sn-master-equal-height],
367 +[data-sn-master-first-row]{
381 381   box-sizing:border-box;
382 382  }
383 383  </style>
384 384  
385 -<script data-sn-horizontal-box-harmonizer="7">
372 +<script data-sn-service-navigator-master="1">
386 386  (function(){
387 387   "use strict";
388 388  
376 + var PAGE_KIND="overview";
377 + var PLACEHOLDER=false;
378 + var PLACEHOLDER_LABEL="COMING SOON";
379 +
389 389   var MOBILE_MAX=767;
390 390   var ROW_TOLERANCE=6;
391 - var MIN_W=150;
392 - var MIN_H=36;
393 - var MAX_PARENT_CHILDREN=18;
394 - var SEARCH_DEPTH=5;
395 395   var RESIZE_DEBOUNCE=220;
396 - var MIN_WIDTH_CHANGE=2;
397 397  
398 398   var root=
399 399   document.getElementById("xwikicontent")||
... ... @@ -403,142 +403,114 @@
403 403  
404 404   if(!root)return;
405 405  
406 - var heightManaged=new Set();
407 - var sectionManaged=new Set();
408 - var contentManaged=new Set();
392 + var managedHeight=new Set();
393 + var managedMargin=new Set();
394 + var originalHeight=new WeakMap();
395 + var originalMargin=new WeakMap();
409 409  
410 - var originalMinHeight=new WeakMap();
411 - var originalMarginTop=new WeakMap();
412 -
413 413   var resizeTimer=0;
414 - var lastWidth=-1;
415 - var hasApplied=false;
416 - var applying=false;
398 + var running=false;
417 417  
418 - function num(v){
419 - var n=parseFloat(v);
420 - return Number.isFinite(n)?n:0;
421 - }
422 -
423 - function visible(el,minW,minH){
424 - if(!el||el.nodeType!==1)return false;
425 -
426 - var s=getComputedStyle(el);
427 -
428 - if(
429 - s.display==="none"||
430 - s.visibility==="hidden"||
431 - Number(s.opacity)===0
432 - ){
433 - return false;
400 + var THEMES=[
401 + {
402 + name:"BLUE",
403 + accent:"#21b6d7",
404 + bg:"#eaf7fb",
405 + text:"#315d68",
406 + labels:[
407 + "HIER STARTEN",
408 + "ENTSCHEIDEN",
409 + "ÜBERPRÜFEN & ANPASSEN",
410 + "START HERE",
411 + "DECIDE",
412 + "REVIEW & ADAPT"
413 + ]
414 + },
415 + {
416 + name:"RED",
417 + accent:"#e94b13",
418 + bg:"#fff1ec",
419 + text:"#8a4d36",
420 + labels:[
421 + "PLANEN & ORGANISIEREN",
422 + "ORGANISIEREN & DOKUMENTIEREN",
423 + "PUBLIZIEREN & PRÄSENTIEREN",
424 + "PLAN & ORGANISE",
425 + "PLAN & ORGANIZE",
426 + "ORGANISE & DOCUMENT",
427 + "ORGANIZE & DOCUMENT",
428 + "PUBLISH & PRESENT"
429 + ]
430 + },
431 + {
432 + name:"YELLOW",
433 + accent:"#f0aa00",
434 + bg:"#fff8e7",
435 + text:"#785b17",
436 + labels:[
437 + "SCHÜTZEN & KLÄREN",
438 + "STANDARDISIEREN & IDENTIFIZIEREN",
439 + "ÖFFNEN, NACHNUTZEN & AUFFINDBAR MACHEN",
440 + "PROTECT & CLARIFY",
441 + "STANDARDISE & IDENTIFY",
442 + "STANDARDIZE & IDENTIFY",
443 + "OPEN, REUSE & MAKE FINDABLE"
444 + ]
445 + },
446 + {
447 + name:"GREEN",
448 + accent:"#38b76a",
449 + bg:"#edf9f1",
450 + text:"#3f7451",
451 + labels:[
452 + "INFRASTRUKTUR EINRICHTEN",
453 + "INFRASTRUKTUR & ZUSAMMENARBEIT EINRICHTEN",
454 + "SPEICHERN & ZUGRIFF STEUERN",
455 + "REPOSITORIUM, ERHALTEN & ÜBERGEBEN",
456 + "SET UP INFRASTRUCTURE",
457 + "SET UP INFRASTRUCTURE & COLLABORATION",
458 + "STORE & CONTROL ACCESS",
459 + "REPOSITORY, PRESERVE & HAND OVER"
460 + ]
434 434   }
462 + ];
435 435  
436 - var r=el.getBoundingClientRect();
437 -
438 - return (
439 - r.width>=(minW||1)&&
440 - r.height>=(minH||1)
441 - );
464 + function num(value){
465 + var n=parseFloat(value);
466 + return Number.isFinite(n)?n:0;
442 442   }
443 443  
444 - function normalizeText(text){
445 - return String(text||"")
469 + function norm(value){
470 + return String(value||"")
446 446   .replace(/\s+/g," ")
447 447   .trim()
448 448   .toUpperCase();
449 449   }
450 450  
451 - function excluded(el){
452 - return (
453 - !el.matches||
454 - el.matches(
455 - "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]"
456 - )
457 - );
458 - }
476 + function visible(el){
477 + if(!el||el.nodeType!==1)return false;
459 459  
460 - /* ---------- Custom coloured callouts ---------- */
479 + var style=getComputedStyle(el);
480 + var rect=el.getBoundingClientRect();
461 461  
462 - function nativeCallout(el){
463 - var c=
464 - typeof el.className==="string"
465 - ? el.className.toLowerCase()
466 - : "";
467 -
468 468   return (
469 - /(^|\s)(infomessage|warningmessage|successmessage|errormessage)(\s|$)/.test(c)
483 + style.display!=="none"&&
484 + style.visibility!=="hidden"&&
485 + rect.width>20&&
486 + rect.height>4
470 470   );
471 471   }
472 472  
473 - function customCallout(el){
474 - if(!visible(el,220,42)||excluded(el))return false;
475 -
476 - var r=el.getBoundingClientRect();
477 -
478 - if(r.height>520)return false;
479 -
480 - var s=getComputedStyle(el);
481 -
482 - var bg=
483 - s.backgroundColor&&
484 - s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
485 - s.backgroundColor!=="transparent"&&
486 - s.backgroundColor!=="rgb(255, 255, 255)";
487 -
488 - var left=
489 - num(s.borderLeftWidth);
490 -
491 - return (
492 - bg&&
493 - left>=2
494 - );
495 - }
496 -
497 - function harmoniseCustomCallouts(){
498 - Array.from(
499 - root.querySelectorAll(
500 - "div,aside,section"
501 - )
502 - ).forEach(function(el){
503 - if(nativeCallout(el))return;
504 - if(!customCallout(el))return;
505 -
506 - var s=getComputedStyle(el);
507 -
508 - el.setAttribute(
509 - "data-sn-callout-harmonized",
510 - "1"
511 - );
512 -
513 - if(
514 - s.borderLeftColor
515 - ){
516 - el.style.setProperty(
517 - "--sn-callout-accent",
518 - s.borderLeftColor
519 - );
520 - }
521 - });
522 - }
523 -
524 - /* ---------- Restore only values V7 itself changed ---------- */
525 -
526 - function saveOriginal(el,map,property){
490 + function saveStyle(el,map,property){
527 527   if(map.has(el))return;
528 528  
529 529   map.set(el,{
530 - value:
531 - el.style.getPropertyValue(
532 - property
533 - ),
534 - priority:
535 - el.style.getPropertyPriority(
536 - property
537 - )
494 + value:el.style.getPropertyValue(property),
495 + priority:el.style.getPropertyPriority(property)
538 538   });
539 539   }
540 540  
541 - function restoreOriginal(el,map,property){
499 + function restoreStyle(el,map,property){
542 542   var original=map.get(el);
543 543  
544 544   if(original&&original.value){
... ... @@ -548,770 +548,845 @@
548 548   original.priority||""
549 549   );
550 550   }else{
551 - el.style.removeProperty(
552 - property
553 - );
509 + el.style.removeProperty(property);
554 554   }
555 555   }
556 556  
557 557   function resetRuntime(){
558 - heightManaged.forEach(function(el){
559 - restoreOriginal(
514 + managedHeight.forEach(function(el){
515 + restoreStyle(
560 560   el,
561 - originalMinHeight,
517 + originalHeight,
562 562   "min-height"
563 563   );
564 -
565 565   el.removeAttribute(
566 - "data-sn-equal-height-managed"
521 + "data-sn-master-equal-height"
567 567   );
568 568   });
569 569  
570 - sectionManaged.forEach(function(el){
571 - restoreOriginal(
525 + managedMargin.forEach(function(el){
526 + restoreStyle(
572 572   el,
573 - originalMarginTop,
528 + originalMargin,
574 574   "margin-top"
575 575   );
576 -
577 577   el.removeAttribute(
578 - "data-sn-first-section-aligned"
532 + "data-sn-master-first-row"
579 579   );
580 580   });
581 581  
582 - contentManaged.forEach(function(el){
583 - restoreOriginal(
584 - el,
585 - originalMarginTop,
586 - "margin-top"
587 - );
588 -
589 - el.removeAttribute(
590 - "data-sn-first-content-aligned"
591 - );
592 - });
593 -
594 - heightManaged.clear();
595 - sectionManaged.clear();
596 - contentManaged.clear();
536 + managedHeight.clear();
537 + managedMargin.clear();
597 597   }
598 598  
599 - /* ---------- Card detection ---------- */
540 + function themeFor(text){
541 + var value=norm(text);
600 600  
601 - function namedLikeBox(el){
602 - var c=
603 - typeof el.className==="string"
604 - ? el.className
605 - : "";
543 + for(var i=0;i<THEMES.length;i++){
544 + for(var j=0;j<THEMES[i].labels.length;j++){
545 + var label=THEMES[i].labels[j];
606 606  
607 - return /(^|[\s_-])(box|card|tile|panel|role|check|service|source|call|area|detail|resource|topic|warn|info)([\s_-]|$)/i.test(c);
547 + if(
548 + value===label||
549 + value.indexOf(label+" ")===0||
550 + value.indexOf(label+" -")===0||
551 + value.indexOf(label+" ·")===0
552 + ){
553 + return THEMES[i];
554 + }
555 + }
556 + }
557 +
558 + return null;
608 608   }
609 609  
610 - function boxLike(el){
561 + /* =======================================================
562 + PLACEHOLDER BADGE
563 + ======================================================= */
564 +
565 + function applyPlaceholderBadge(){
566 + if(!PLACEHOLDER)return;
567 +
611 611   if(
612 - !visible(el,MIN_W,MIN_H)||
613 - excluded(el)
569 + document.querySelector(
570 + ".sn-coming-soon-badge"
571 + )
614 614   ){
615 - return false;
573 + return;
616 616   }
617 617  
618 - var s=getComputedStyle(el);
619 - var r=el.getBoundingClientRect();
576 + var title=
577 + document.querySelector(
578 + "#document-title"
579 + )||
580 + document.querySelector(
581 + "h1"
582 + );
620 620  
621 - var border=
622 - num(s.borderTopWidth)+
623 - num(s.borderRightWidth)+
624 - num(s.borderBottomWidth)+
625 - num(s.borderLeftWidth);
584 + if(!title)return;
626 626  
627 - var radius=Math.max(
628 - num(s.borderTopLeftRadius),
629 - num(s.borderTopRightRadius),
630 - num(s.borderBottomLeftRadius),
631 - num(s.borderBottomRightRadius)
586 + var badge=
587 + document.createElement(
588 + "span"
589 + );
590 +
591 + badge.className=
592 + "sn-coming-soon-badge";
593 +
594 + badge.textContent=
595 + PLACEHOLDER_LABEL;
596 +
597 + badge.setAttribute(
598 + "aria-label",
599 + PLACEHOLDER_LABEL
632 632   );
633 633  
634 - var bg=
635 - s.backgroundColor&&
636 - s.backgroundColor!=="rgba(0, 0, 0, 0)"&&
637 - s.backgroundColor!=="transparent";
602 + title.appendChild(
603 + badge
604 + );
605 + }
638 638  
639 - var shadow=
640 - s.boxShadow&&
641 - s.boxShadow!=="none";
607 + /* =======================================================
608 + DETAIL PAGE OWN-ACCENT PROPAGATION
609 + ======================================================= */
642 642  
643 - return (
644 - namedLikeBox(el)||
645 - border>=1||
646 - (bg&&radius>=3)||
647 - (shadow&&r.width>=180)
611 + function parseRGB(value){
612 + var match=String(value||"").match(
613 + /rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i
648 648   );
615 +
616 + if(!match)return null;
617 +
618 + return [
619 + Number(match[1]),
620 + Number(match[2]),
621 + Number(match[3])
622 + ];
649 649   }
650 650  
651 - function pickTarget(child){
652 - if(!visible(child,MIN_W,MIN_H))return null;
625 + function distance(a,b){
626 + return Math.sqrt(
627 + Math.pow(a[0]-b[0],2)+
628 + Math.pow(a[1]-b[1],2)+
629 + Math.pow(a[2]-b[2],2)
630 + );
631 + }
653 653  
654 - if(boxLike(child))return child;
633 + function paletteMatch(cssColor){
634 + var rgb=parseRGB(cssColor);
655 655  
656 - var cr=child.getBoundingClientRect();
657 - var q=[];
636 + if(!rgb)return null;
658 658  
659 - Array.from(child.children||[]).forEach(function(el){
660 - q.push({el:el,depth:1});
661 - });
638 + var palette=[
639 + {hex:"#21b6d7",rgb:[33,182,215]},
640 + {hex:"#e94b13",rgb:[233,75,19]},
641 + {hex:"#f0aa00",rgb:[240,170,0]},
642 + {hex:"#38b76a",rgb:[56,183,106]}
643 + ];
662 662  
663 663   var best=null;
664 - var bestScore=-Infinity;
646 + var bestDistance=Infinity;
665 665  
666 - while(q.length){
667 - var item=q.shift();
668 - var el=item.el;
648 + palette.forEach(function(item){
649 + var d=distance(rgb,item.rgb);
669 669  
670 - if(!visible(el,MIN_W,MIN_H))continue;
651 + if(d<bestDistance){
652 + best=item;
653 + bestDistance=d;
654 + }
655 + });
671 671  
672 - var r=el.getBoundingClientRect();
657 + return bestDistance<=30
658 + ?best
659 + :null;
660 + }
673 673  
662 + function propagateDetailAccents(){
663 + if(PAGE_KIND!=="detail")return;
664 +
665 + Array.from(
666 + root.querySelectorAll(
667 + ".arsn-call,.dmp-call,.ido-call,.pp-call,"+
668 + ".arsn-source,.dmp-source,.ido-source,.pp-source"
669 + )
670 + ).forEach(function(el){
671 + if(!visible(el))return;
672 +
673 + var style=getComputedStyle(el);
674 +
674 674   if(
675 - r.width>=cr.width*.68&&
676 - boxLike(el)
676 + num(style.borderTopWidth)>=2
677 677   ){
678 - var widthFit=
679 - 1-Math.min(
680 - 1,
681 - Math.abs(cr.width-r.width)/
682 - Math.max(1,cr.width)
678 + var match=
679 + paletteMatch(
680 + style.borderTopColor
683 683   );
684 684  
685 - var topFit=
686 - 1-Math.min(
687 - 1,
688 - Math.abs(cr.top-r.top)/100
683 + if(match){
684 + el.style.setProperty(
685 + "border-left",
686 + "4px solid "+match.hex,
687 + "important"
689 689   );
690 -
691 - var score=
692 - widthFit*6+
693 - topFit*3+
694 - Math.min(r.height,900)/450+
695 - Math.min(r.width*r.height,900000)/900000;
696 -
697 - if(score>bestScore){
698 - best=el;
699 - bestScore=score;
700 700   }
701 701   }
691 + });
702 702  
703 - if(item.depth<SEARCH_DEPTH){
704 - Array.from(el.children||[]).forEach(function(next){
705 - q.push({
706 - el:next,
707 - depth:item.depth+1
708 - });
709 - });
710 - }
711 - }
693 + // Warning families: explicit safety override.
694 + Array.from(
695 + root.querySelectorAll(
696 + ".arsn-warn,.dmp-warn,.ido-warn,.pp-warn,"+
697 + ".warn,.warning,.warningmessage,.errormessage"
698 + )
699 + ).forEach(function(el){
700 + if(!visible(el))return;
712 712  
713 - return best;
714 - }
702 + el.style.setProperty(
703 + "border-left",
704 + "4px solid #e94b13",
705 + "important"
706 + );
707 + });
715 715  
716 - function groupRows(entries){
717 - var groups=[];
709 + // Info families: explicit orientation override.
710 + Array.from(
711 + root.querySelectorAll(
712 + ".arsn-info,.dmp-info,.ido-info,.pp-info,.infomessage"
713 + )
714 + ).forEach(function(el){
715 + if(!visible(el))return;
718 718  
719 - entries
720 - .slice()
721 - .sort(function(a,b){
722 - return (
723 - a.rect.top-b.rect.top||
724 - a.rect.left-b.rect.left
725 - );
726 - })
727 - .forEach(function(entry){
728 - var group=null;
717 + el.style.setProperty(
718 + "border-left",
719 + "4px solid #21b6d7",
720 + "important"
721 + );
722 + });
723 + }
729 729  
730 - for(var i=0;i<groups.length;i++){
731 - if(
732 - Math.abs(
733 - groups[i].top-
734 - entry.rect.top
735 - )<=ROW_TOLERANCE
736 - ){
737 - group=groups[i];
738 - break;
739 - }
740 - }
725 + /* =======================================================
726 + OVERVIEW SEMANTIC THEME PALETTE
727 + ======================================================= */
741 741  
742 - if(!group){
743 - group={
744 - top:entry.rect.top,
745 - entries:[]
746 - };
747 - groups.push(group);
748 - }
729 + function smallestThemeHeaders(){
730 + return Array.from(
731 + root.querySelectorAll(
732 + "div,span,p,strong,h3,h4,h5,h6"
733 + )
734 + ).filter(function(el){
735 + if(!visible(el))return false;
736 + if(!themeFor(el.textContent))return false;
749 749  
750 - group.entries.push(entry);
738 + return !Array.from(
739 + el.children||[]
740 + ).some(function(child){
741 + return !!themeFor(
742 + child.textContent
743 + );
751 751   });
752 -
753 - return groups;
745 + });
754 754   }
755 755  
756 - function validRow(group){
757 - if(group.entries.length<2)return false;
748 + function findOverviewCard(header){
749 + var node=header.parentElement;
750 + var candidates=[];
758 758  
759 - var lefts=
760 - group.entries
761 - .map(function(e){return e.rect.left;})
762 - .sort(function(a,b){return a-b;});
752 + while(node&&node!==root){
753 + var rect=node.getBoundingClientRect();
754 + var style=getComputedStyle(node);
763 763  
764 - if(
765 - lefts[lefts.length-1]-
766 - lefts[0]<
767 - 80
768 - ){
769 - return false;
770 - }
756 + var border=
757 + num(style.borderTopWidth)+
758 + num(style.borderRightWidth)+
759 + num(style.borderBottomWidth)+
760 + num(style.borderLeftWidth);
771 771  
772 - var widths=
773 - group.entries
774 - .map(function(e){return e.rect.width;})
775 - .filter(function(w){return w>0;});
762 + if(
763 + rect.width>=220&&
764 + rect.width<=800&&
765 + rect.height>=120&&
766 + border>=1
767 + ){
768 + candidates.push(node);
769 + }
776 776  
777 - if(widths.length<2)return false;
771 + node=node.parentElement;
772 + }
778 778  
779 - var minW=
780 - Math.min.apply(Math,widths);
774 + if(!candidates.length)return null;
781 781  
782 - var maxW=
783 - Math.max.apply(Math,widths);
784 -
785 - return (
786 - maxW/
787 - Math.max(1,minW)<=
788 - 1.9
789 - );
790 - }
791 -
792 - /* ---------- Known ARSN first section bars ---------- */
793 -
794 - function knownBar(el){
795 - var text=
796 - normalizeText(
797 - el.textContent
776 + candidates.sort(function(a,b){
777 + return (
778 + b.getBoundingClientRect().height-
779 + a.getBoundingClientRect().height
798 798   );
781 + });
799 799  
800 - return (
801 - text==="HIER STARTEN"||
802 - text==="ORGANISIEREN & DOKUMENTIEREN"||
803 - text==="ENTSCHEIDEN"||
804 - text==="START HERE"||
805 - text==="GET STARTED"||
806 - text==="ORGANISE & DOCUMENT"||
807 - text==="ORGANIZE & DOCUMENT"||
808 - text==="DECIDE"
809 - );
783 + return candidates[0];
810 810   }
811 811  
812 - function findKnownBar(card){
786 + function rowCandidates(link,card){
787 + var result=[];
813 813   var cardRect=
814 814   card.getBoundingClientRect();
815 815  
816 - var rows=
817 - Array.from(
818 - card.querySelectorAll(
819 - "div,p,span,strong,h3,h4,h5,h6"
820 - )
821 - )
822 - .filter(function(el){
823 - if(!visible(el,20,6))return false;
824 - if(!knownBar(el))return false;
791 + var node=link;
825 825  
826 - var r=el.getBoundingClientRect();
793 + while(node&&node!==card){
794 + if(visible(node)){
795 + var rect=
796 + node.getBoundingClientRect();
827 827  
828 - var rel=
829 - r.top-
830 - cardRect.top;
798 + if(
799 + rect.height<=105&&
800 + rect.width>=
801 + cardRect.width*.50&&
802 + rect.width<=
803 + cardRect.width*1.03
804 + ){
805 + result.push(node);
806 + }
807 + }
831 831  
809 + node=node.parentElement;
810 + }
811 +
812 + return result;
813 + }
814 +
815 + function chooseOuterRow(
816 + candidates,
817 + link
818 + ){
819 + if(!candidates.length){
820 + return link;
821 + }
822 +
823 + var bordered=
824 + candidates.filter(function(el){
832 832   return (
833 - rel>=35&&
834 - rel<=
835 - cardRect.height*.75
826 + num(
827 + getComputedStyle(el)
828 + .borderLeftWidth
829 + )>=1
836 836   );
837 - })
838 - .sort(function(a,b){
839 - return (
840 - a.getBoundingClientRect().top-
841 - b.getBoundingClientRect().top
842 - );
843 843   });
844 844  
845 - return rows[0]||null;
846 - }
833 + var pool=
834 + bordered.length
835 + ?bordered
836 + :candidates;
847 847  
848 - function alignKnownBars(cards){
849 - var rows=
850 - cards.map(function(card){
851 - var bar=
852 - findKnownBar(card);
838 + pool.sort(function(a,b){
839 + var ar=
840 + a.getBoundingClientRect();
853 853  
854 - if(!bar)return null;
842 + var br=
843 + b.getBoundingClientRect();
855 855  
856 - var cr=
857 - card.getBoundingClientRect();
845 + return (
846 + ar.left-br.left||
847 + br.width-ar.width
848 + );
849 + });
858 858  
859 - var br=
860 - bar.getBoundingClientRect();
851 + return pool[0]||link;
852 + }
861 861  
862 - return {
863 - bar:bar,
864 - relativeTop:
865 - br.top-
866 - cr.top
867 - };
868 - });
869 -
870 - if(
871 - rows.some(function(row){
872 - return !row;
873 - })
874 - ){
875 - return false;
854 + function applyOverviewPalette(){
855 + if(PAGE_KIND!=="overview"){
856 + return [];
876 876   }
877 877  
878 - var target=
879 - Math.max.apply(
880 - Math,
881 - rows.map(function(row){
882 - return row.relativeTop;
859 + var headers=
860 + smallestThemeHeaders()
861 + .map(function(el){
862 + return {
863 + el:el,
864 + theme:
865 + themeFor(
866 + el.textContent
867 + ),
868 + card:
869 + findOverviewCard(
870 + el
871 + )
872 + };
883 883   })
884 - );
874 + .filter(function(row){
875 + return !!row.card;
876 + });
885 885  
886 - rows.forEach(function(row){
887 - var delta=
888 - target-
889 - row.relativeTop;
878 + var unique=[];
879 + var seenHeaders=new Set();
890 890  
891 - if(delta<=1)return;
881 + headers.forEach(function(row){
882 + var key=
883 + row.theme.name+
884 + "|"+
885 + Math.round(
886 + row.card
887 + .getBoundingClientRect()
888 + .left
889 + )+
890 + "|"+
891 + Math.round(
892 + row.el
893 + .getBoundingClientRect()
894 + .top
895 + );
892 892  
893 - saveOriginal(
894 - row.bar,
895 - originalMarginTop,
896 - "margin-top"
897 - );
897 + if(!seenHeaders.has(key)){
898 + seenHeaders.add(key);
899 + unique.push(row);
900 + }
901 + });
898 898  
899 - var current=
900 - num(
901 - getComputedStyle(
902 - row.bar
903 - ).marginTop
904 - );
903 + unique.forEach(function(row){
904 + var headerRect=
905 + row.el
906 + .getBoundingClientRect();
905 905  
906 - row.bar.style.setProperty(
907 - "margin-top",
908 - (
909 - current+
910 - delta
911 - )+"px"
908 + row.el.style.setProperty(
909 + "background",
910 + row.theme.bg,
911 + "important"
912 912   );
913 913  
914 - row.bar.setAttribute(
915 - "data-sn-first-section-aligned",
916 - "7"
914 + row.el.style.setProperty(
915 + "color",
916 + row.theme.text,
917 + "important"
917 917   );
918 918  
919 - sectionManaged.add(
920 - row.bar
920 + row.el.style.setProperty(
921 + "text-align",
922 + "left",
923 + "important"
921 921   );
922 - });
923 923  
924 - return true;
925 - }
926 + row.el.style.setProperty(
927 + "word-spacing",
928 + "normal",
929 + "important"
930 + );
926 926  
927 - /* ---------- Generic first content after heading ---------- */
932 + var later=
933 + unique
934 + .filter(function(other){
935 + return (
936 + other.card===row.card&&
937 + other.el
938 + .getBoundingClientRect()
939 + .top>
940 + headerRect.top+2
941 + );
942 + })
943 + .sort(function(a,b){
944 + return (
945 + a.el
946 + .getBoundingClientRect()
947 + .top-
948 + b.el
949 + .getBoundingClientRect()
950 + .top
951 + );
952 + });
928 928  
929 - function heading(card){
930 - var cr=
931 - card.getBoundingClientRect();
954 + var stopTop=
955 + later.length
956 + ?later[0].el
957 + .getBoundingClientRect()
958 + .top
959 + :Infinity;
932 932  
933 - var rows=
934 934   Array.from(
935 - card.querySelectorAll(
936 - "h1,h2,h3,h4,h5,h6,.box-title,[role=heading]"
937 - )
938 - )
939 - .filter(function(el){
940 - if(!visible(el,20,8))return false;
962 + row.card.querySelectorAll("a")
963 + ).forEach(function(link){
964 + if(!visible(link))return;
941 941  
942 - var r=el.getBoundingClientRect();
966 + var rect=
967 + link.getBoundingClientRect();
943 943  
944 - var rel=
945 - r.top-
946 - cr.top;
947 -
948 - return (
949 - rel>=0&&
950 - rel<=
951 - Math.min(
952 - 160,
953 - cr.height*.45
954 - )
955 - );
956 - })
957 - .sort(function(a,b){
958 - return (
959 - a.getBoundingClientRect().top-
960 - b.getBoundingClientRect().top
961 - );
962 - });
963 -
964 - return rows[0]||null;
965 - }
966 -
967 - function firstContent(card,h){
968 - if(!h)return null;
969 -
970 - var cr=
971 - card.getBoundingClientRect();
972 -
973 - var hr=
974 - h.getBoundingClientRect();
975 -
976 - var rows=
977 - Array.from(
978 - card.querySelectorAll(
979 - "p,div,ul,ol,dl,blockquote"
980 - )
981 - )
982 - .filter(function(el){
983 983   if(
984 - el===h||
985 - h.contains(el)||
986 - el.contains(h)
970 + rect.top<=
971 + headerRect.bottom-2||
972 + rect.top>=
973 + stopTop-2
987 987   ){
988 - return false;
975 + return;
989 989   }
990 990  
991 - if(!visible(el,30,8))return false;
978 + var candidates=
979 + rowCandidates(
980 + link,
981 + row.card
982 + );
992 992  
993 - var text=
994 - String(el.textContent||"")
995 - .replace(/\s+/g," ")
996 - .trim();
984 + var target=
985 + chooseOuterRow(
986 + candidates,
987 + link
988 + );
997 997  
998 - if(text.length<3)return false;
990 + candidates.forEach(function(el){
991 + el.style.setProperty(
992 + "border-left",
993 + "0 solid transparent",
994 + "important"
995 + );
996 + });
999 999  
1000 - var r=el.getBoundingClientRect();
998 + target.style.setProperty(
999 + "border-left",
1000 + "3px solid "+
1001 + row.theme.accent,
1002 + "important"
1003 + );
1001 1001  
1002 - if(
1003 - r.top<
1004 - hr.bottom-1
1005 - ){
1006 - return false;
1007 - }
1008 -
1009 - if(
1010 - r.top-cr.top>
1011 - Math.min(
1012 - 280,
1013 - cr.height*.65
1014 - )
1015 - ){
1016 - return false;
1017 - }
1018 -
1019 - if(
1020 - r.height>
1021 - cr.height*.58
1022 - ){
1023 - return false;
1024 - }
1025 -
1026 - return true;
1027 - })
1028 - .sort(function(a,b){
1029 - var ar=
1030 - a.getBoundingClientRect();
1031 -
1032 - var br=
1033 - b.getBoundingClientRect();
1034 -
1035 - return (
1036 - ar.top-br.top||
1037 - ar.height-br.height
1005 + target.style.setProperty(
1006 + "box-sizing",
1007 + "border-box",
1008 + "important"
1038 1038   );
1039 1039   });
1011 + });
1040 1040  
1041 - return rows[0]||null;
1013 + return unique;
1042 1042   }
1043 1043  
1044 - function alignGeneric(cards){
1045 - var rows=
1046 - cards.map(function(card){
1047 - var h=
1048 - heading(card);
1016 + /* =======================================================
1017 + OVERVIEW CARD HEIGHT + FIRST THEMATIC ROW
1018 + ======================================================= */
1049 1049  
1050 - var c=
1051 - firstContent(
1052 - card,
1053 - h
1054 - );
1055 -
1056 - if(!h||!c)return null;
1057 -
1058 - var cr=
1059 - card.getBoundingClientRect();
1060 -
1061 - var rr=
1062 - c.getBoundingClientRect();
1063 -
1064 - return {
1065 - content:c,
1066 - relativeTop:
1067 - rr.top-cr.top
1068 - };
1069 - });
1070 -
1020 + function alignOverviewCards(headers){
1071 1071   if(
1072 - rows.some(function(row){
1073 - return !row;
1074 - })
1022 + PAGE_KIND!=="overview"||
1023 + window.innerWidth<=MOBILE_MAX
1075 1075   ){
1076 - return false;
1025 + return;
1077 1077   }
1078 1078  
1079 - var target=
1080 - Math.max.apply(
1081 - Math,
1082 - rows.map(function(row){
1083 - return row.relativeTop;
1084 - })
1085 - );
1028 + var cards=[];
1029 + var seen=new Set();
1086 1086  
1087 - rows.forEach(function(row){
1088 - var delta=
1089 - target-
1090 - row.relativeTop;
1031 + headers.forEach(function(row){
1032 + if(!seen.has(row.card)){
1033 + seen.add(row.card);
1034 + cards.push(row.card);
1035 + }
1036 + });
1091 1091  
1092 - if(delta<=1)return;
1038 + if(cards.length<2){
1039 + return;
1040 + }
1093 1093  
1094 - saveOriginal(
1095 - row.content,
1096 - originalMarginTop,
1097 - "margin-top"
1098 - );
1042 + // Group cards by actual top position.
1043 + var groups=[];
1099 1099  
1100 - var current=
1101 - num(
1102 - getComputedStyle(
1103 - row.content
1104 - ).marginTop
1105 - );
1045 + cards.forEach(function(card){
1046 + var top=
1047 + card.getBoundingClientRect().top;
1106 1106  
1107 - row.content.style.setProperty(
1108 - "margin-top",
1109 - (
1110 - current+
1111 - delta
1112 - )+"px"
1113 - );
1049 + var group=null;
1114 1114  
1115 - row.content.setAttribute(
1116 - "data-sn-first-content-aligned",
1117 - "7"
1118 - );
1051 + for(var i=0;i<groups.length;i++){
1052 + if(
1053 + Math.abs(
1054 + groups[i].top-top
1055 + )<=ROW_TOLERANCE
1056 + ){
1057 + group=groups[i];
1058 + break;
1059 + }
1060 + }
1119 1119  
1120 - contentManaged.add(
1121 - row.content
1122 - );
1062 + if(!group){
1063 + group={
1064 + top:top,
1065 + cards:[]
1066 + };
1067 + groups.push(group);
1068 + }
1069 +
1070 + group.cards.push(card);
1123 1123   });
1124 1124  
1125 - return true;
1126 - }
1073 + groups.forEach(function(group){
1074 + if(group.cards.length<2){
1075 + return;
1076 + }
1127 1127  
1128 - function applyRow(group){
1129 - if(!validRow(group))return false;
1078 + var firstHeaders=
1079 + group.cards.map(function(card){
1080 + var candidates=
1081 + headers
1082 + .filter(function(row){
1083 + return row.card===card;
1084 + })
1085 + .sort(function(a,b){
1086 + return (
1087 + a.el
1088 + .getBoundingClientRect()
1089 + .top-
1090 + b.el
1091 + .getBoundingClientRect()
1092 + .top
1093 + );
1094 + });
1130 1130  
1131 - var cards=[];
1132 - var seen=new Set();
1096 + return candidates.length
1097 + ?candidates[0]
1098 + :null;
1099 + });
1133 1133  
1134 - group.entries.forEach(function(entry){
1135 - if(!seen.has(entry.target)){
1136 - seen.add(entry.target);
1137 - cards.push(entry.target);
1138 - }
1139 - });
1101 + if(
1102 + !firstHeaders.some(function(row){
1103 + return !row;
1104 + })
1105 + ){
1106 + var targetTop=
1107 + Math.max.apply(
1108 + Math,
1109 + firstHeaders.map(function(row){
1110 + return (
1111 + row.el
1112 + .getBoundingClientRect()
1113 + .top-
1114 + row.card
1115 + .getBoundingClientRect()
1116 + .top
1117 + );
1118 + })
1119 + );
1140 1140  
1141 - if(cards.length<2)return false;
1121 + firstHeaders.forEach(function(row){
1122 + var relativeTop=
1123 + row.el
1124 + .getBoundingClientRect()
1125 + .top-
1126 + row.card
1127 + .getBoundingClientRect()
1128 + .top;
1142 1142  
1143 - if(
1144 - !alignKnownBars(cards)
1145 - ){
1146 - alignGeneric(cards);
1147 - }
1130 + var delta=
1131 + targetTop-relativeTop;
1148 1148  
1149 - var maxHeight=0;
1133 + if(delta>1){
1134 + saveStyle(
1135 + row.el,
1136 + originalMargin,
1137 + "margin-top"
1138 + );
1150 1150  
1151 - cards.forEach(function(card){
1152 - maxHeight=
1153 - Math.max(
1154 - maxHeight,
1155 - card.getBoundingClientRect().height
1156 - );
1157 - });
1140 + var current=
1141 + num(
1142 + getComputedStyle(
1143 + row.el
1144 + ).marginTop
1145 + );
1158 1158  
1159 - maxHeight=
1160 - Math.ceil(
1161 - maxHeight
1162 - );
1147 + row.el.style.setProperty(
1148 + "margin-top",
1149 + (
1150 + current+delta
1151 + )+"px"
1152 + );
1163 1163  
1164 - if(maxHeight<MIN_H)return false;
1154 + row.el.setAttribute(
1155 + "data-sn-master-first-row",
1156 + "1"
1157 + );
1165 1165  
1166 - cards.forEach(function(card){
1167 - saveOriginal(
1168 - card,
1169 - originalMinHeight,
1170 - "min-height"
1171 - );
1159 + managedMargin.add(
1160 + row.el
1161 + );
1162 + }
1163 + });
1164 + }
1172 1172  
1173 - card.style.setProperty(
1174 - "min-height",
1175 - maxHeight+"px"
1176 - );
1166 + var maxHeight=0;
1177 1177  
1178 - card.setAttribute(
1179 - "data-sn-equal-height-managed",
1180 - "7"
1181 - );
1168 + group.cards.forEach(function(card){
1169 + maxHeight=
1170 + Math.max(
1171 + maxHeight,
1172 + card
1173 + .getBoundingClientRect()
1174 + .height
1175 + );
1176 + });
1182 1182  
1183 - heightManaged.add(card);
1184 - });
1178 + maxHeight=
1179 + Math.ceil(maxHeight);
1185 1185  
1186 - return true;
1187 - }
1181 + group.cards.forEach(function(card){
1182 + saveStyle(
1183 + card,
1184 + originalHeight,
1185 + "min-height"
1186 + );
1188 1188  
1189 - function calculate(force){
1190 - if(applying)return;
1188 + card.style.setProperty(
1189 + "min-height",
1190 + maxHeight+"px"
1191 + );
1191 1191  
1192 - var width=
1193 - Math.round(
1194 - window.innerWidth
1195 - );
1193 + card.setAttribute(
1194 + "data-sn-master-equal-height",
1195 + "1"
1196 + );
1196 1196  
1197 - var meaningful=
1198 - lastWidth<0||
1199 - Math.abs(
1200 - width-
1201 - lastWidth
1202 - )>=
1203 - MIN_WIDTH_CHANGE;
1198 + managedHeight.add(
1199 + card
1200 + );
1201 + });
1202 + });
1203 + }
1204 1204  
1205 + /* =======================================================
1206 + DETAIL GRID EQUAL HEIGHT, DESKTOP ONLY
1207 + ======================================================= */
1208 +
1209 + function equaliseDetailGrids(){
1205 1205   if(
1206 - hasApplied&&
1207 - !force&&
1208 - !meaningful
1211 + PAGE_KIND!=="detail"||
1212 + window.innerWidth<=MOBILE_MAX
1209 1209   ){
1210 1210   return;
1211 1211   }
1212 1212  
1213 - applying=true;
1217 + var selectors=[
1218 + ".arsn-grid",
1219 + ".arsn-grid-2",
1220 + ".arsn-grid-3",
1221 + ".dmp-grid",
1222 + ".ido-grid",
1223 + ".pp-grid"
1224 + ];
1214 1214  
1215 - try{
1216 - harmoniseCustomCallouts();
1226 + selectors.forEach(function(selector){
1227 + Array.from(
1228 + root.querySelectorAll(selector)
1229 + ).forEach(function(grid){
1230 + var children=
1231 + Array.from(
1232 + grid.children||[]
1233 + ).filter(visible);
1217 1217  
1218 - if(width<=MOBILE_MAX){
1219 - if(hasApplied){
1220 - resetRuntime();
1235 + if(children.length<2){
1236 + return;
1221 1221   }
1222 1222  
1223 - hasApplied=false;
1224 - lastWidth=width;
1225 - return;
1226 - }
1239 + var groups=[];
1227 1227  
1228 - if(hasApplied){
1229 - resetRuntime();
1230 - }
1241 + children.forEach(function(child){
1242 + var top=
1243 + child
1244 + .getBoundingClientRect()
1245 + .top;
1231 1231  
1232 - var parents=
1233 - Array.from(
1234 - root.querySelectorAll("*")
1235 - )
1236 - .filter(function(parent){
1237 - return (
1238 - visible(
1239 - parent,
1240 - MIN_W,
1241 - MIN_H
1242 - )&&
1243 - parent.children&&
1244 - parent.children.length>=2&&
1245 - parent.children.length<=
1246 - MAX_PARENT_CHILDREN
1247 - );
1248 - });
1247 + var group=null;
1249 1249  
1250 - var touched=
1251 - new Set();
1249 + for(var i=0;i<groups.length;i++){
1250 + if(
1251 + Math.abs(
1252 + groups[i].top-top
1253 + )<=ROW_TOLERANCE
1254 + ){
1255 + group=groups[i];
1256 + break;
1257 + }
1258 + }
1252 1252  
1253 - parents.forEach(function(parent){
1254 - var entries=[];
1260 + if(!group){
1261 + group={
1262 + top:top,
1263 + items:[]
1264 + };
1265 + groups.push(group);
1266 + }
1255 1255  
1256 - Array.from(
1257 - parent.children
1258 - ).forEach(function(child){
1259 - if(
1260 - !visible(
1261 - child,
1262 - MIN_W,
1263 - MIN_H
1264 - )
1265 - ){
1268 + group.items.push(child);
1269 + });
1270 +
1271 + groups.forEach(function(group){
1272 + if(group.items.length<2){
1266 1266   return;
1267 1267   }
1268 1268  
1269 - var target=
1270 - pickTarget(child);
1276 + var maxHeight=0;
1271 1271  
1272 - if(!target)return;
1273 -
1274 - entries.push({
1275 - target:target,
1276 - rect:
1277 - target.getBoundingClientRect()
1278 + group.items.forEach(function(item){
1279 + maxHeight=
1280 + Math.max(
1281 + maxHeight,
1282 + item
1283 + .getBoundingClientRect()
1284 + .height
1285 + );
1278 1278   });
1279 - });
1280 1280  
1281 - groupRows(
1282 - entries
1283 - ).forEach(function(group){
1284 - if(!validRow(group))return;
1288 + maxHeight=
1289 + Math.ceil(maxHeight);
1285 1285  
1286 - var targets=
1287 - group.entries.map(function(entry){
1288 - return entry.target;
1289 - });
1291 + group.items.forEach(function(item){
1292 + saveStyle(
1293 + item,
1294 + originalHeight,
1295 + "min-height"
1296 + );
1290 1290  
1291 - if(
1292 - !targets.some(function(el){
1293 - return !touched.has(el);
1294 - })
1295 - ){
1296 - return;
1297 - }
1298 + item.style.setProperty(
1299 + "min-height",
1300 + maxHeight+"px"
1301 + );
1298 1298  
1299 - if(applyRow(group)){
1300 - targets.forEach(function(el){
1301 - touched.add(el);
1302 - });
1303 - }
1303 + item.setAttribute(
1304 + "data-sn-master-equal-height",
1305 + "1"
1306 + );
1307 +
1308 + managedHeight.add(item);
1309 + });
1304 1304   });
1305 1305   });
1312 + });
1313 + }
1306 1306  
1307 - lastWidth=width;
1308 - hasApplied=true;
1315 + /* =======================================================
1316 + RUN / RESPONSIVE SCHEDULING
1317 + ======================================================= */
1318 +
1319 + function run(){
1320 + if(running)return;
1321 +
1322 + running=true;
1323 +
1324 + try{
1325 + resetRuntime();
1326 + applyPlaceholderBadge();
1327 + propagateDetailAccents();
1328 +
1329 + var headers=
1330 + applyOverviewPalette();
1331 +
1332 + if(
1333 + window.innerWidth>
1334 + MOBILE_MAX
1335 + ){
1336 + alignOverviewCards(
1337 + headers
1338 + );
1339 +
1340 + equaliseDetailGrids();
1341 + }
1309 1309   }finally{
1310 - applying=false;
1343 + running=false;
1311 1311   }
1312 1312   }
1313 1313  
1314 - function resize(){
1347 + function onResize(){
1315 1315   if(resizeTimer){
1316 1316   clearTimeout(
1317 1317   resizeTimer
... ... @@ -1322,19 +1322,40 @@
1322 1322   setTimeout(
1323 1323   function(){
1324 1324   resizeTimer=0;
1325 - calculate(false);
1358 + run();
1326 1326   },
1327 1327   RESIZE_DEBOUNCE
1328 1328   );
1329 1329   }
1330 1330  
1331 - function waitImages(){
1364 + async function waitForReady(){
1365 + if(
1366 + document.readyState!=="complete"
1367 + ){
1368 + await new Promise(function(resolve){
1369 + window.addEventListener(
1370 + "load",
1371 + resolve,
1372 + {once:true}
1373 + );
1374 + });
1375 + }
1376 +
1377 + if(
1378 + document.fonts&&
1379 + document.fonts.ready
1380 + ){
1381 + try{
1382 + await document.fonts.ready;
1383 + }catch(error){}
1384 + }
1385 +
1332 1332   var images=
1333 1333   Array.from(
1334 1334   root.querySelectorAll("img")
1335 1335   );
1336 1336  
1337 - return Promise.all(
1391 + await Promise.all(
1338 1338   images.map(function(img){
1339 1339   if(img.complete){
1340 1340   return Promise.resolve();
... ... @@ -1359,46 +1359,20 @@
1359 1359   });
1360 1360   })
1361 1361   );
1362 - }
1363 1363  
1364 - async function initial(){
1365 - if(
1366 - document.readyState!==
1367 - "complete"
1368 - ){
1369 - await new Promise(function(resolve){
1370 - addEventListener(
1371 - "load",
1372 - resolve,
1373 - {once:true}
1374 - );
1375 - });
1376 - }
1377 -
1378 - if(
1379 - document.fonts&&
1380 - document.fonts.ready
1381 - ){
1382 - try{
1383 - await document.fonts.ready;
1384 - }catch(error){}
1385 - }
1386 -
1387 - await waitImages();
1388 -
1389 - // Exactly one initial layout calculation.
1390 - calculate(true);
1417 + run();
1391 1391   }
1392 1392  
1393 - addEventListener(
1420 + window.addEventListener(
1394 1394   "resize",
1395 - resize,
1422 + onResize,
1396 1396   {passive:true}
1397 1397   );
1398 1398  
1399 - initial();
1426 + waitForReady();
1400 1400  })();
1401 1401  </script>
1402 1402  
1403 -<!-- SN_HORIZONTAL_BOX_HARMONIZER_END -->
1404 -{{/html}}\n
1430 +<!-- SN_SERVICE_NAVIGATOR_MASTER_STYLE_END -->
1431 +{{/html}}
1432 +