From 933dbf69ceccb31889802f6fa95852215536d033 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 18:04:56 +0000 Subject: [PATCH] The phone had no export at all, and the kill-switch only ever covered the desktop RM-EXPORT-KILLSWITCH + RM-RTL-PHYSICAL, from exp's country-posters diff. Both cards are worth doing and neither is quite what it says. EXPORT. LegendDesktop takes :export-enabled="EXPORT_FEATURE_ENABLED", so turning the flag off hides the desktop menu. LegendMobile is OPT-IN BY CONSTRUCTION -- its exportEnabled is `typeof inject('onLegendExport') === 'function'` (LegendMobile.vue:393) -- and this profile provided nothing at all. So the flag was not being IGNORED on mobile; there was no mobile export to ignore it. A reader on a phone had no way to export a poster or a packet while the same map on a desktop did, which is the opposite complaint and a worse one. Providing it unguarded would then have created exactly the bug the card names: a phone keeping an affordance the desktop deliberately hides. So it is provided the way country-posters already does it, guarded by the same flag, and mobile export exists for the first time here. RTL. The card says research-map uses physical CSS where country-posters uses logical. MEASURED: the rules in question are BYTE-IDENTICAL in both files -- .rm-error, .rm-badge and .map-scroll-edge--left/right are the same physical declarations either side. They are part of the 811 shared lines between these two maps, so neither is ahead of the other and fixing "the gap" would have been fixing nothing. Two of them are genuinely wrong for RTL and are fixed here: .rm-badge is pinned to the READING edge, so inset-inline-end; and .dg-field strong's gap is margin-inline-end. Both exist identically in country-posters and are exp's to mirror. .map-scroll-edge--left/right STAY PHYSICAL, deliberately: they are literal screen edges for a scroll affordance and do not mirror. .rm-error's left:12px/right:12px is symmetric and mirrors to itself. Converting either would be churn dressed as an RTL fix. --- .../doxa-research-map/research-map.vue | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugin-designs/doxa-research-map/research-map.vue b/plugin-designs/doxa-research-map/research-map.vue index b3ef9b559..17a6757e9 100644 --- a/plugin-designs/doxa-research-map/research-map.vue +++ b/plugin-designs/doxa-research-map/research-map.vue @@ -268,7 +268,7 @@ useShadowStyles(` .dg-main { font-weight:500;font-size:13px;color:#222;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:flex;align-items:center;gap:6px; } .dg-main strong { font-weight:700;overflow:hidden;text-overflow:ellipsis; } .dg-meta { margin-top:2px;display:flex;flex-wrap:wrap;gap:4px 10px;font-size:11px;color:#555;line-height:1.35; } - .dg-field strong { font-weight:600;color:#333;margin-right:2px; } + .dg-field strong { font-weight:600;color:#333;margin-inline-end:2px; } /* Round 16 — labeled category tag replacing the old emoji prefixes. */ .dg-tag { flex:none;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.4px;color:#3b463d;background:rgba(59,70,61,0.10);border-radius:4px;padding:1px 5px;line-height:1.5;white-space:nowrap; } .dg-agg-label { overflow:hidden;text-overflow:ellipsis; } @@ -438,7 +438,10 @@ useShadowStyles(` map did manage to render stays visible around it. A spinner that outlives the failure reads as "slow" and the user just waits; this says the map is gone. */ .rm-error { position:absolute;top:50%;left:12px;right:12px;z-index:7;transform:translateY(-50%);text-align:center;font:13px/1.5 -apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;color:#fecaca;background:rgba(15,18,22,.95);border:1px solid rgba(254,202,202,.28);border-radius:10px;padding:12px 14px;box-shadow:0 2px 10px rgba(0,0,0,.4); } - .rm-badge { position:absolute;top:10px;right:10px;background:rgba(124,140,248,0.12);color:#7c8cf8;border:1px solid rgba(124,140,248,0.3);padding:3px 9px;border-radius:4px;font-size:11px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;pointer-events:none;z-index:50; } + /* inset-inline-end, not right: this badge is pinned to the READING edge, so under ar it belongs on + the left. .map-scroll-edge--left/right below stay physical on purpose — those are literal screen + edges for a scroll affordance and do not mirror. */ + .rm-badge { position:absolute;top:10px;inset-inline-end:10px;background:rgba(124,140,248,0.12);color:#7c8cf8;border:1px solid rgba(124,140,248,0.3);padding:3px 9px;border-radius:4px;font-size:11px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;pointer-events:none;z-index:50; } /* Engine badge — bottom-left, unobtrusive. Colour differs per engine so a side-by-side comparison is readable at a glance. */ .rm-provider-badge { position:absolute;bottom:8px;left:8px;z-index:50;pointer-events:none;padding:2px 8px;border-radius:999px;font:600 10px/1.6 -apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;letter-spacing:.04em;color:#fff;background:rgba(30,41,59,0.72);border:1px solid rgba(255,255,255,0.18);backdrop-filter:blur(2px); } @@ -1503,6 +1506,15 @@ function onExport(kind) { if (kind === 'poster') return openPoster() if (kind === 'packet') return openPacket() } +// ★ THE PHONE HAD NO EXPORT AT ALL, AND THE KILL-SWITCH ONLY COVERED THE DESKTOP. +// LegendDesktop takes :export-enabled="EXPORT_FEATURE_ENABLED", so turning that flag off hid the +// desktop menu — but LegendMobile is OPT-IN BY CONSTRUCTION: its exportEnabled is +// `typeof inject('onLegendExport') === 'function'` (LegendMobile.vue:393), and this profile provided +// nothing. So a reader on a phone had no way to export a poster or a packet, while the same map on a +// desktop did. country-posters already carries the guarded line; this is the missing half here. +// Providing it UNGUARDED would be the other error — the phone would then keep an affordance the +// desktop deliberately hides whenever the flag is off, which is the bug exp's card names. +provide('onLegendExport', EXPORT_FEATURE_ENABLED ? onExport : null) // ─── Packet export (printed, multi-page: map + a card per people group) ────── // Lazy-loaded on first use, the same pattern openPoster() uses. Defensive throughout: never throw