Commit c98b602 h
Changes: 3 files +75 -43
Changes (Side-by-Side)
share/jenny/layout/page.sh +25 -19
diagram_script() { | |||
| 172 | var content = document.createElement('div'); |
172 | var content = document.createElement('div'); |
| 173 | content.className = 'diagram-modal-content'; |
173 | content.className = 'diagram-modal-content'; |
| 174 | |
174 | |
| 175 | var header = document.createElement('div'); |
||
| 176 | header.className = 'diagram-modal-header'; |
||
| 177 | header.setAttribute('aria-hidden', 'true'); |
||
| 178 | |
||
| 179 | var closeBtn = document.createElement('button'); |
175 | var closeBtn = document.createElement('button'); |
| 180 | closeBtn.className = 'diagram-modal-close'; |
176 | closeBtn.className = 'diagram-modal-close'; |
| 181 | closeBtn.setAttribute('aria-label', 'Close diagram'); |
177 | closeBtn.setAttribute('aria-label', 'Close diagram'); |
| 182 | closeBtn.innerHTML = '✕︎'; |
178 | closeBtn.innerHTML = '✕︎'; |
| 183 | closeBtn.addEventListener('click', closeModal); |
179 | closeBtn.addEventListener('click', closeModal); |
| 184 | |
180 | |
| 185 | header.appendChild(closeBtn); |
||
| 186 | |
||
| 187 | var body = document.createElement('div'); |
181 | var body = document.createElement('div'); |
| 188 | body.className = 'diagram-modal-body'; |
182 | body.className = 'diagram-modal-body'; |
| 189 | |
183 | |
| 190 | content.appendChild(header); |
||
| 184 | content.appendChild(closeBtn); |
||
| 191 | content.appendChild(body); |
185 | content.appendChild(body); |
| 192 | m.appendChild(backdrop); |
186 | m.appendChild(backdrop); |
| 193 | m.appendChild(content); |
187 | m.appendChild(content); |
cat << _EOF_ | |||
| 920 | transform: none; |
914 | transform: none; |
| 921 | } |
915 | } |
| 922 | } |
916 | } |
| 923 | /* Diagram modal: full-screen display for dense flowcharts */ |
||
| 917 | /* Diagram modal: full-screen display for dense flowcharts. The point is |
||
| 918 | to give a dense chart the whole screen, so the content box fills the |
||
| 919 | viewport rather than shrink-wrapping the diagram. An earlier version |
||
| 920 | capped it at min(95vw, 95vh); on any landscape screen 95vh is the |
||
| 921 | smaller of the two, so a 1440x900 viewport held the diagram to 855px |
||
| 922 | and threw away 513px of usable width. */ |
||
| 924 | .diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000; |
923 | .diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000; |
| 925 | background-color: var(--modal-backdrop); overflow: auto; } |
924 | background-color: var(--modal-backdrop); overflow: auto; } |
| 926 | .diagram-modal[open] { display: flex; align-items: center; justify-content: center; } |
||
| 925 | .diagram-modal[open] { display: flex; } |
||
| 927 | .diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; } |
926 | .diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; } |
| 928 | .diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary); |
927 | .diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary); |
| 929 | border: 1px solid var(--border-light); border-radius: 3px; |
||
| 930 | max-width: min(95vw, 95vh); max-height: 95vh; |
||
| 931 | overflow: auto; display: flex; flex-direction: column; } |
||
| 932 | .diagram-modal-header { display: flex; align-items: center; justify-content: space-between; |
||
| 933 | padding: 0.75em 1em; border-bottom: 1px solid var(--border-light); |
||
| 934 | flex-shrink: 0; } |
||
| 935 | .diagram-modal-close { background: none; border: none; font-size: 1.5em; |
||
| 928 | width: 100%; height: 100%; overflow: auto; display: flex; } |
||
| 929 | /* No header bar: the close button floats over the diagram so nothing |
||
| 930 | frames it but the viewport edge. */ |
||
| 931 | .diagram-modal-close { position: absolute; top: 0.5em; right: 0.5em; z-index: 2; |
||
| 932 | background: var(--bg-primary); border: 1px solid var(--border-light); |
||
| 933 | border-radius: 3px; width: 2em; height: 2em; font-size: 1.25em; |
||
| 936 | color: var(--text-primary); cursor: pointer; padding: 0; |
934 | color: var(--text-primary); cursor: pointer; padding: 0; |
| 937 | line-height: 1; } |
||
| 935 | line-height: 1; display: flex; align-items: center; |
||
| 936 | justify-content: center; } |
||
| 938 | .diagram-modal-close:hover { opacity: 0.7; } |
937 | .diagram-modal-close:hover { opacity: 0.7; } |
| 939 | .diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center; |
938 | .diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center; |
| 940 | justify-content: center; padding: 1em; } |
||
| 941 | .diagram-modal-svg { max-width: 100%; max-height: 100%; width: auto; height: auto; } |
||
| 939 | justify-content: center; padding: 1.5em; min-width: 0; } |
||
| 940 | /* mermaid writes an inline style="max-width: {natural}px" on the <svg> |
||
| 941 | it renders, which an ordinary stylesheet rule cannot beat -- inline |
||
| 942 | styles win over a selector however specific. Without !important the |
||
| 943 | diagram stays at its natural width in a full-screen modal, which is |
||
| 944 | the whole thing the modal is for. The viewBox makes it scale |
||
| 945 | cleanly, so height follows the aspect ratio on its own. */ |
||
| 946 | .diagram-modal-svg { max-width: 100% !important; max-height: 100%; |
||
| 947 | width: 100%; height: auto; } |
||
| 942 | |
948 | |
| 943 | </style> |
949 | </style> |
| 944 | <script> |
950 | <script> |
share/jenny/layout/post.sh +25 -19
diagram_script() { | |||
| 88 | var content = document.createElement('div'); |
88 | var content = document.createElement('div'); |
| 89 | content.className = 'diagram-modal-content'; |
89 | content.className = 'diagram-modal-content'; |
| 90 | |
90 | |
| 91 | var header = document.createElement('div'); |
||
| 92 | header.className = 'diagram-modal-header'; |
||
| 93 | header.setAttribute('aria-hidden', 'true'); |
||
| 94 | |
||
| 95 | var closeBtn = document.createElement('button'); |
91 | var closeBtn = document.createElement('button'); |
| 96 | closeBtn.className = 'diagram-modal-close'; |
92 | closeBtn.className = 'diagram-modal-close'; |
| 97 | closeBtn.setAttribute('aria-label', 'Close diagram'); |
93 | closeBtn.setAttribute('aria-label', 'Close diagram'); |
| 98 | closeBtn.innerHTML = '✕︎'; |
94 | closeBtn.innerHTML = '✕︎'; |
| 99 | closeBtn.addEventListener('click', closeModal); |
95 | closeBtn.addEventListener('click', closeModal); |
| 100 | |
96 | |
| 101 | header.appendChild(closeBtn); |
||
| 102 | |
||
| 103 | var body = document.createElement('div'); |
97 | var body = document.createElement('div'); |
| 104 | body.className = 'diagram-modal-body'; |
98 | body.className = 'diagram-modal-body'; |
| 105 | |
99 | |
| 106 | content.appendChild(header); |
||
| 100 | content.appendChild(closeBtn); |
||
| 107 | content.appendChild(body); |
101 | content.appendChild(body); |
| 108 | m.appendChild(backdrop); |
102 | m.appendChild(backdrop); |
| 109 | m.appendChild(content); |
103 | m.appendChild(content); |
cat << _EOF_ | |||
| 741 | transform: none; |
735 | transform: none; |
| 742 | } |
736 | } |
| 743 | } |
737 | } |
| 744 | /* Diagram modal: full-screen display for dense flowcharts */ |
||
| 738 | /* Diagram modal: full-screen display for dense flowcharts. The point is |
||
| 739 | to give a dense chart the whole screen, so the content box fills the |
||
| 740 | viewport rather than shrink-wrapping the diagram. An earlier version |
||
| 741 | capped it at min(95vw, 95vh); on any landscape screen 95vh is the |
||
| 742 | smaller of the two, so a 1440x900 viewport held the diagram to 855px |
||
| 743 | and threw away 513px of usable width. */ |
||
| 745 | .diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000; |
744 | .diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000; |
| 746 | background-color: var(--modal-backdrop); overflow: auto; } |
745 | background-color: var(--modal-backdrop); overflow: auto; } |
| 747 | .diagram-modal[open] { display: flex; align-items: center; justify-content: center; } |
||
| 746 | .diagram-modal[open] { display: flex; } |
||
| 748 | .diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; } |
747 | .diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; } |
| 749 | .diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary); |
748 | .diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary); |
| 750 | border: 1px solid var(--border-light); border-radius: 3px; |
||
| 751 | max-width: min(95vw, 95vh); max-height: 95vh; |
||
| 752 | overflow: auto; display: flex; flex-direction: column; } |
||
| 753 | .diagram-modal-header { display: flex; align-items: center; justify-content: space-between; |
||
| 754 | padding: 0.75em 1em; border-bottom: 1px solid var(--border-light); |
||
| 755 | flex-shrink: 0; } |
||
| 756 | .diagram-modal-close { background: none; border: none; font-size: 1.5em; |
||
| 749 | width: 100%; height: 100%; overflow: auto; display: flex; } |
||
| 750 | /* No header bar: the close button floats over the diagram so nothing |
||
| 751 | frames it but the viewport edge. */ |
||
| 752 | .diagram-modal-close { position: absolute; top: 0.5em; right: 0.5em; z-index: 2; |
||
| 753 | background: var(--bg-primary); border: 1px solid var(--border-light); |
||
| 754 | border-radius: 3px; width: 2em; height: 2em; font-size: 1.25em; |
||
| 757 | color: var(--text-primary); cursor: pointer; padding: 0; |
755 | color: var(--text-primary); cursor: pointer; padding: 0; |
| 758 | line-height: 1; } |
||
| 756 | line-height: 1; display: flex; align-items: center; |
||
| 757 | justify-content: center; } |
||
| 759 | .diagram-modal-close:hover { opacity: 0.7; } |
758 | .diagram-modal-close:hover { opacity: 0.7; } |
| 760 | .diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center; |
759 | .diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center; |
| 761 | justify-content: center; padding: 1em; } |
||
| 762 | .diagram-modal-svg { max-width: 100%; max-height: 100%; width: auto; height: auto; } |
||
| 760 | justify-content: center; padding: 1.5em; min-width: 0; } |
||
| 761 | /* mermaid writes an inline style="max-width: {natural}px" on the <svg> |
||
| 762 | it renders, which an ordinary stylesheet rule cannot beat -- inline |
||
| 763 | styles win over a selector however specific. Without !important the |
||
| 764 | diagram stays at its natural width in a full-screen modal, which is |
||
| 765 | the whole thing the modal is for. The viewBox makes it scale |
||
| 766 | cleanly, so height follows the aspect ratio on its own. */ |
||
| 767 | .diagram-modal-svg { max-width: 100% !important; max-height: 100%; |
||
| 768 | width: 100%; height: auto; } |
||
| 763 | </style> |
769 | </style> |
| 764 | <script> |
770 | <script> |
| 765 | (function() { |
771 | (function() { |
test/regressions.sh +25 -5
assert_file_contains "$dm_post" "clone.setAttribute('class', 'diagram-modal-svg' | |||
| 2625 | assert_file_not_contains "$dm_post" "clone.className =" |
2625 | assert_file_not_contains "$dm_post" "clone.className =" |
| 2626 | |
2626 | |
| 2627 | it "modal SVG is constrained by max-width and max-height" |
2627 | it "modal SVG is constrained by max-width and max-height" |
| 2628 | # CSS rule ensures the diagram doesn't exceed the modal container. |
||
| 2629 | assert_file_contains "$dm_post" ".diagram-modal-svg { max-width: 100%; max-height: 100%" |
||
| 2628 | # The diagram must not exceed the modal, and must be free to grow to fill it. |
||
| 2629 | # This asserted the rule without !important, which is the form mermaid's inline |
||
| 2630 | # style overrides -- another assertion that matched the broken code exactly. |
||
| 2631 | assert_file_contains "$dm_post" ".diagram-modal-svg { max-width: 100% !important; max-height: 100%" |
||
| 2630 | |
2632 | |
| 2631 | it "focus is given to modal when opened" |
2633 | it "focus is given to modal when opened" |
| 2632 | # The modal must take focus for keyboard accessibility. |
2634 | # The modal must take focus for keyboard accessibility. |
it "keyboard events are prevented to avoid page scroll" | |||
| 2659 | # preventDefault must stop Space from scrolling the page. |
2661 | # preventDefault must stop Space from scrolling the page. |
| 2660 | assert_file_contains "$dm_post" "e.preventDefault()" |
2662 | assert_file_contains "$dm_post" "e.preventDefault()" |
| 2661 | |
2663 | |
| 2662 | it "modal content is centered in the viewport" |
||
| 2663 | # The modal must use flexbox to center its content. |
||
| 2664 | assert_file_contains "$dm_post" ".diagram-modal[open] { display: flex; align-items: center; justify-content: center" |
||
| 2664 | it "the diagram is centred inside the modal" |
||
| 2665 | # Centring moved to the body: the content box now fills the viewport, so it is |
||
| 2666 | # the diagram inside it that gets centred, not the box within the screen. |
||
| 2667 | assert_file_contains "$dm_post" ".diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center;" |
||
| 2668 | |
||
| 2669 | it "the modal content box fills the viewport" |
||
| 2670 | # It used to be capped at min(95vw, 95vh). On any landscape screen 95vh is the |
||
| 2671 | # smaller term, so a 1440x900 viewport held the diagram to 855px and wasted |
||
| 2672 | # 513px of width -- the opposite of what a full-screen view is for. |
||
| 2673 | assert_file_contains "$dm_post" "width: 100%; height: 100%; overflow: auto; display: flex; }" |
||
| 2674 | assert_file_not_contains "$dm_post" "max-width: min(95vw, 95vh)" |
||
| 2675 | |
||
| 2676 | it "the diagram overrides mermaid's inline max-width" |
||
| 2677 | # mermaid writes style="max-width: {natural}px" directly on the <svg>. An |
||
| 2678 | # inline style beats any selector, so without !important the diagram keeps its |
||
| 2679 | # natural width and never grows to fill the modal. |
||
| 2680 | assert_file_contains "$dm_post" "max-width: 100% !important" |
||
| 2681 | |
||
| 2682 | it "the modal has no chrome around the diagram" |
||
| 2683 | # Just a close button floating over the diagram; no header bar, no frame. |
||
| 2684 | assert_file_not_contains "$dm_post" "diagram-modal-header" |
||
| 2665 | |
2685 | |
| 2666 | it "modal is removed from the normal flow" |
2686 | it "modal is removed from the normal flow" |
| 2667 | # position:fixed takes the modal out of the document flow. |
2687 | # position:fixed takes the modal out of the document flow. |
Raw
commit c98b602a2dbd5eda2cea013e54ddcdc7fd9ca09a
Author: Pat Ambrosio <cp.ambrosio@gmail.com>
Date: Fri Aug 28 09:53:05 2026 +0800
Give the diagram modal the whole viewport, and no chrome
Two things kept a full-screen viewer from being full-screen.
The content box was capped at max-width: min(95vw, 95vh). On any screen
wider than it is tall, 95vh is the smaller term, so the cap was driven by
height: a 1440x900 viewport held the diagram to 855px and threw away
513px of usable width. The box now fills the viewport.
Underneath that, mermaid writes style="max-width: {natural}px" directly
on the <svg> it renders. An inline style beats a stylesheet rule however
specific the selector, so even with the cap gone a diagram would have sat
at its natural size inside a full-screen box. Hence the !important, which
is not habit here: measured in a DOM, the computed max-width is 300px
without it and 100% with it. The viewBox handles the rest, so height can
stay auto and the aspect ratio follows.
The chrome goes with it: no header bar, no border, no radius. The close
button floats over the top-right corner and nothing frames the diagram
but the edge of the screen.
One more test asserted the implementation verbatim -- the SVG sizing rule
in its pre-!important form, which is exactly the form mermaid overrides.
That is the third such assertion in this feature, after clone.className
and the 95vh cap. All three passed against broken behaviour because they
compared the code to itself. Each now states the working form and fails
against the broken one; reverting the !important fails two tests.
diff --git a/share/jenny/layout/page.sh b/share/jenny/layout/page.sh
index fc7fdf6..040778b 100755
--- a/share/jenny/layout/page.sh
+++ b/share/jenny/layout/page.sh
@@ -172,22 +172,16 @@ diagram_script() {
var content = document.createElement('div');
content.className = 'diagram-modal-content';
- var header = document.createElement('div');
- header.className = 'diagram-modal-header';
- header.setAttribute('aria-hidden', 'true');
-
var closeBtn = document.createElement('button');
closeBtn.className = 'diagram-modal-close';
closeBtn.setAttribute('aria-label', 'Close diagram');
closeBtn.innerHTML = '✕︎';
closeBtn.addEventListener('click', closeModal);
- header.appendChild(closeBtn);
-
var body = document.createElement('div');
body.className = 'diagram-modal-body';
- content.appendChild(header);
+ content.appendChild(closeBtn);
content.appendChild(body);
m.appendChild(backdrop);
m.appendChild(content);
@@ -920,25 +914,37 @@ cat << _EOF_
transform: none;
}
}
- /* Diagram modal: full-screen display for dense flowcharts */
+ /* Diagram modal: full-screen display for dense flowcharts. The point is
+ to give a dense chart the whole screen, so the content box fills the
+ viewport rather than shrink-wrapping the diagram. An earlier version
+ capped it at min(95vw, 95vh); on any landscape screen 95vh is the
+ smaller of the two, so a 1440x900 viewport held the diagram to 855px
+ and threw away 513px of usable width. */
.diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000;
background-color: var(--modal-backdrop); overflow: auto; }
- .diagram-modal[open] { display: flex; align-items: center; justify-content: center; }
+ .diagram-modal[open] { display: flex; }
.diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; }
.diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary);
- border: 1px solid var(--border-light); border-radius: 3px;
- max-width: min(95vw, 95vh); max-height: 95vh;
- overflow: auto; display: flex; flex-direction: column; }
- .diagram-modal-header { display: flex; align-items: center; justify-content: space-between;
- padding: 0.75em 1em; border-bottom: 1px solid var(--border-light);
- flex-shrink: 0; }
- .diagram-modal-close { background: none; border: none; font-size: 1.5em;
+ width: 100%; height: 100%; overflow: auto; display: flex; }
+ /* No header bar: the close button floats over the diagram so nothing
+ frames it but the viewport edge. */
+ .diagram-modal-close { position: absolute; top: 0.5em; right: 0.5em; z-index: 2;
+ background: var(--bg-primary); border: 1px solid var(--border-light);
+ border-radius: 3px; width: 2em; height: 2em; font-size: 1.25em;
color: var(--text-primary); cursor: pointer; padding: 0;
- line-height: 1; }
+ line-height: 1; display: flex; align-items: center;
+ justify-content: center; }
.diagram-modal-close:hover { opacity: 0.7; }
.diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center;
- justify-content: center; padding: 1em; }
- .diagram-modal-svg { max-width: 100%; max-height: 100%; width: auto; height: auto; }
+ justify-content: center; padding: 1.5em; min-width: 0; }
+ /* mermaid writes an inline style="max-width: {natural}px" on the <svg>
+ it renders, which an ordinary stylesheet rule cannot beat -- inline
+ styles win over a selector however specific. Without !important the
+ diagram stays at its natural width in a full-screen modal, which is
+ the whole thing the modal is for. The viewBox makes it scale
+ cleanly, so height follows the aspect ratio on its own. */
+ .diagram-modal-svg { max-width: 100% !important; max-height: 100%;
+ width: 100%; height: auto; }
</style>
<script>
diff --git a/share/jenny/layout/post.sh b/share/jenny/layout/post.sh
index 7885517..ba0be6a 100755
--- a/share/jenny/layout/post.sh
+++ b/share/jenny/layout/post.sh
@@ -88,22 +88,16 @@ diagram_script() {
var content = document.createElement('div');
content.className = 'diagram-modal-content';
- var header = document.createElement('div');
- header.className = 'diagram-modal-header';
- header.setAttribute('aria-hidden', 'true');
-
var closeBtn = document.createElement('button');
closeBtn.className = 'diagram-modal-close';
closeBtn.setAttribute('aria-label', 'Close diagram');
closeBtn.innerHTML = '✕︎';
closeBtn.addEventListener('click', closeModal);
- header.appendChild(closeBtn);
-
var body = document.createElement('div');
body.className = 'diagram-modal-body';
- content.appendChild(header);
+ content.appendChild(closeBtn);
content.appendChild(body);
m.appendChild(backdrop);
m.appendChild(content);
@@ -741,25 +735,37 @@ cat << _EOF_
transform: none;
}
}
- /* Diagram modal: full-screen display for dense flowcharts */
+ /* Diagram modal: full-screen display for dense flowcharts. The point is
+ to give a dense chart the whole screen, so the content box fills the
+ viewport rather than shrink-wrapping the diagram. An earlier version
+ capped it at min(95vw, 95vh); on any landscape screen 95vh is the
+ smaller of the two, so a 1440x900 viewport held the diagram to 855px
+ and threw away 513px of usable width. */
.diagram-modal { display: none; position: fixed; inset: 0; z-index: 2000;
background-color: var(--modal-backdrop); overflow: auto; }
- .diagram-modal[open] { display: flex; align-items: center; justify-content: center; }
+ .diagram-modal[open] { display: flex; }
.diagram-modal-backdrop { position: absolute; inset: 0; z-index: -1; }
.diagram-modal-content { position: relative; z-index: 1; background-color: var(--bg-primary);
- border: 1px solid var(--border-light); border-radius: 3px;
- max-width: min(95vw, 95vh); max-height: 95vh;
- overflow: auto; display: flex; flex-direction: column; }
- .diagram-modal-header { display: flex; align-items: center; justify-content: space-between;
- padding: 0.75em 1em; border-bottom: 1px solid var(--border-light);
- flex-shrink: 0; }
- .diagram-modal-close { background: none; border: none; font-size: 1.5em;
+ width: 100%; height: 100%; overflow: auto; display: flex; }
+ /* No header bar: the close button floats over the diagram so nothing
+ frames it but the viewport edge. */
+ .diagram-modal-close { position: absolute; top: 0.5em; right: 0.5em; z-index: 2;
+ background: var(--bg-primary); border: 1px solid var(--border-light);
+ border-radius: 3px; width: 2em; height: 2em; font-size: 1.25em;
color: var(--text-primary); cursor: pointer; padding: 0;
- line-height: 1; }
+ line-height: 1; display: flex; align-items: center;
+ justify-content: center; }
.diagram-modal-close:hover { opacity: 0.7; }
.diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center;
- justify-content: center; padding: 1em; }
- .diagram-modal-svg { max-width: 100%; max-height: 100%; width: auto; height: auto; }
+ justify-content: center; padding: 1.5em; min-width: 0; }
+ /* mermaid writes an inline style="max-width: {natural}px" on the <svg>
+ it renders, which an ordinary stylesheet rule cannot beat -- inline
+ styles win over a selector however specific. Without !important the
+ diagram stays at its natural width in a full-screen modal, which is
+ the whole thing the modal is for. The viewBox makes it scale
+ cleanly, so height follows the aspect ratio on its own. */
+ .diagram-modal-svg { max-width: 100% !important; max-height: 100%;
+ width: 100%; height: auto; }
</style>
<script>
(function() {
diff --git a/test/regressions.sh b/test/regressions.sh
index e968be3..714fc4f 100755
--- a/test/regressions.sh
+++ b/test/regressions.sh
@@ -2625,8 +2625,10 @@ assert_file_contains "$dm_post" "clone.setAttribute('class', 'diagram-modal-svg'
assert_file_not_contains "$dm_post" "clone.className ="
it "modal SVG is constrained by max-width and max-height"
-# CSS rule ensures the diagram doesn't exceed the modal container.
-assert_file_contains "$dm_post" ".diagram-modal-svg { max-width: 100%; max-height: 100%"
+# The diagram must not exceed the modal, and must be free to grow to fill it.
+# This asserted the rule without !important, which is the form mermaid's inline
+# style overrides -- another assertion that matched the broken code exactly.
+assert_file_contains "$dm_post" ".diagram-modal-svg { max-width: 100% !important; max-height: 100%"
it "focus is given to modal when opened"
# The modal must take focus for keyboard accessibility.
@@ -2659,9 +2661,27 @@ it "keyboard events are prevented to avoid page scroll"
# preventDefault must stop Space from scrolling the page.
assert_file_contains "$dm_post" "e.preventDefault()"
-it "modal content is centered in the viewport"
-# The modal must use flexbox to center its content.
-assert_file_contains "$dm_post" ".diagram-modal[open] { display: flex; align-items: center; justify-content: center"
+it "the diagram is centred inside the modal"
+# Centring moved to the body: the content box now fills the viewport, so it is
+# the diagram inside it that gets centred, not the box within the screen.
+assert_file_contains "$dm_post" ".diagram-modal-body { flex: 1; overflow: auto; display: flex; align-items: center;"
+
+it "the modal content box fills the viewport"
+# It used to be capped at min(95vw, 95vh). On any landscape screen 95vh is the
+# smaller term, so a 1440x900 viewport held the diagram to 855px and wasted
+# 513px of width -- the opposite of what a full-screen view is for.
+assert_file_contains "$dm_post" "width: 100%; height: 100%; overflow: auto; display: flex; }"
+assert_file_not_contains "$dm_post" "max-width: min(95vw, 95vh)"
+
+it "the diagram overrides mermaid's inline max-width"
+# mermaid writes style="max-width: {natural}px" directly on the <svg>. An
+# inline style beats any selector, so without !important the diagram keeps its
+# natural width and never grows to fill the modal.
+assert_file_contains "$dm_post" "max-width: 100% !important"
+
+it "the modal has no chrome around the diagram"
+# Just a close button floating over the diagram; no header bar, no frame.
+assert_file_not_contains "$dm_post" "diagram-modal-header"
it "modal is removed from the normal flow"
# position:fixed takes the modal out of the document flow.