diff --git a/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue b/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue
index 8b2fb618b..a75f02dd3 100644
--- a/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue
+++ b/plugin-designs/gospel-internet/src/components/GiCenteredSet.vue
@@ -18,7 +18,7 @@
* because a table cannot carry a row it does not have. They are shown separately because
* folding any of them together turns a gap in our knowledge into a claim about a people.
*/
-import { ref, computed, onMounted } from 'vue'
+import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
import { formatCount } from '@map/utils/formatCount.js'
import { useBoardState } from '../useBoard.js'
@@ -35,6 +35,22 @@ const near = ref(null)
// Which ring the reader has asked about. null = none; the chart dims the others rather than
// hiding them, because a ring with no dots left would read as a ring with no groups.
const activeRing = ref(null)
+// ★ ON A NARROW PANE THE TARGET IS THE MAIN VIEW. Side by side there is room for both, but
+// stacked the decoder is a tall card that pushes the chart off the screen — the reader asked to
+// see the target and got a glossary. So below the breakpoint the legend starts CLOSED behind a
+// toggle. It is not hidden: the control names it, and opening is one tap.
+const narrow = ref(false)
+const legendOpen = ref(true)
+let mq = null
+function applyWidth(m) { narrow.value = m.matches; legendOpen.value = !m.matches }
+onMounted(() => {
+ try {
+ mq = window.matchMedia('(max-width: 900px)')
+ applyWidth(mq)
+ mq.addEventListener?.('change', applyWidth)
+ } catch (_) { /* no matchMedia: stay wide, which is the layout that always fits */ }
+})
+onBeforeUnmount(() => { try { mq?.removeEventListener?.('change', applyWidth) } catch (_) {} })
// The panel element, so full screen shows the chart AND its legend rather than one of them.
const panelEl = ref(null)
@@ -102,8 +118,11 @@ useShadowStyles(
'.gcs-fig{position:relative;flex:1 1 auto;align-self:stretch;min-width:0;min-height:240px;' +
'display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:hidden}' +
'.gcs-aside{flex:0 1 340px;min-width:0;min-height:0;overflow:auto;display:flex;align-items:flex-start}' +
+ '.gcs-legend-toggle{width:100%;padding:6px 10px;border:1px solid #d1d4cd;border-radius:8px;' +
+ 'background:#fff;color:#3b463d;font:inherit;font-size:12.5px;cursor:pointer;text-align:start}' +
'@media (max-width:900px){.gcs{flex-direction:column;overflow:auto}' +
- '.gcs-aside{overflow:visible;align-self:stretch}}' +
+ '.gcs-aside{overflow:visible;align-self:stretch;flex:0 0 auto;flex-direction:column;gap:6px}' +
+ '.gcs-aside.collapsed{max-height:44px}}' +
'.gcs svg{max-width:100%;max-height:100%}' +
'.gcs-ring{fill:none;stroke:#d1d4cd;stroke-width:1}' +
'.gcs-arrow{stroke:#92b195;stroke-width:.6;opacity:.5}' +
@@ -130,7 +149,16 @@ useShadowStyles(
-
+
+
-
diff --git a/plugin-designs/gospel-resources/resources-map.vue b/plugin-designs/gospel-resources/resources-map.vue
index dae1fb796..336edc7a5 100644
--- a/plugin-designs/gospel-resources/resources-map.vue
+++ b/plugin-designs/gospel-resources/resources-map.vue
@@ -1978,9 +1978,9 @@ useShadowStyles(
// Collapsed, the panel must SHRINK TO THE CARET. Hiding the contents alone would leave a
// 380px box of empty background sitting over the map — the reader would have pressed
// collapse and got a blank panel instead of their map back, which is worse than no control.
- '.gm-legend.closed{width:auto;padding:4px;background:rgba(243,243,241,.92)}' +
- '.gm-legend.closed .gm-collapse{position:static;inset:auto}' +
- '.gm-collapse{position:absolute;inset-block-start:8px;inset-inline-end:8px;width:22px;height:20px;' +
+ '.gm-legend.closed{width:auto;padding:6px 8px;background:rgba(243,243,241,.92)}' +
+ '.gm-legend.closed .gm-head{margin-bottom:0}' +
+ '.gm-collapse{flex-shrink:0;width:22px;height:20px;' +
'display:flex;align-items:center;justify-content:center;background:rgba(209,212,205,.4);' +
'border:1px solid #d1d4cd;border-radius:5px;cursor:pointer;color:#6d766e;padding:0;' +
'transition:transform .3s ease-out,color .1s,background .1s;transform-origin:center}' +
@@ -1988,7 +1988,8 @@ useShadowStyles(
'.gm-collapse svg{transition:transform .18s;transform:rotate(180deg)}' +
'.gm-collapse.closed svg{transform:rotate(0deg)}' +
'.is-dark .gm-legend{background:rgba(19,32,25,.95);color:#e5e7eb}' +
- '.gm-title{font-weight:700;font-size:15.5px;margin-bottom:5px}' +
+ '.gm-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:5px}' +
+ '.gm-title{font-weight:700;font-size:15.5px}' +
'.gm-keys{display:flex;flex-wrap:wrap;gap:5px 12px}' +
'.gm-key{display:flex;align-items:center;gap:5px;font-size:14px;white-space:nowrap}' +
// This one label is a phrase, not a legend word, so it is allowed to wrap rather than
@@ -2244,20 +2245,6 @@ useShadowStyles(