Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build/pages/index.en.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="fonts.css?v=20260821">
<link rel="stylesheet" href="tokens.css?v=20260822">
<link rel="stylesheet" href="style.css?v=20260822g">
<link rel="stylesheet" href="style.css?v=20260822h">
<script src="i18n.js?v=20260821"></script>
<script src="i18n-data.js?v=20260821"></script>
<script src="i18n-map.js?v=20260822"></script>
<script src="i18n-map.js?v=20260822b"></script>
<script src="theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -466,6 +466,6 @@ <h2 id="introTitle">Follow the water. Protect its pathways.</h2>
<script src="fmt.js?v=20260822"></script>
<script src="gschg31.js?v=20260821"></script>
<script src="legal-alerts.js?v=20260822"></script>
<script src="app.js?v=20260822g"></script>
<script src="app.js?v=20260822h"></script>
</body>
</html>
17 changes: 15 additions & 2 deletions scripts/verify-site.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,12 @@ for (const [label, pattern] of [
['sidebar map readout', /#workspace #tooltip\s*\{[^}]*position:\s*static;[^}]*border-bottom:/s],
['sidebar legal screen', /#workspace #liveAlerts\s*\{[^}]*flex:\s*none;[^}]*border-bottom:/s],
['touch-sized legal screen', /#workspace #liveAlertsToggle\s*\{[^}]*min-height:\s*44px/s],
['viewport-bound legal details', /#workspace #liveAlertsBody\s*\{[^}]*max-height:\s*clamp\(100px,\s*18dvh,\s*180px\);[^}]*overflow-y:\s*auto/s],
['smallest-phone legal details', /@media \(max-width:\s*480px\) and \(max-height:\s*650px\) and \(orientation:\s*portrait\)[\s\S]*?#workspace #liveAlertsBody\s*\{[^}]*max-height:\s*70px/s],
['single-scroll legal details', /#workspace #liveAlertsBody\s*\{[^}]*max-height:\s*none;[^}]*overflow-y:\s*visible/s],
['readable legal explanation', /#workspace \.liveAlertLimit\s*\{[^}]*font-size:\s*13px;[^}]*line-height:\s*1\.55/s],
['full-screen reading mode', /body\.workspaceReading #workspace\s*\{[^}]*inset:\s*0;[^}]*width:\s*100vw;[^}]*height:\s*100dvh/s],
['persistent map return', /#workspaceBack\s*\{[^}]*min-height:\s*38px/s],
['full reading detail surface', /body\.workspaceReading #workspace #panel\s*\{[^}]*inset:\s*var\(--workspace-head-h,\s*99px\) 0 0/s],
['adaptive phone reading height', /body:is\(\.readingLegal, \.readingDetail, \.readingBrief\)\s*\{\s*--workspace-h:\s*72dvh/s],
['persistent project navigation', /#workspaceHead #siteNav\s*\{[^}]*flex-wrap:\s*nowrap;[^}]*overflow-x:\s*auto/s],
['high-contrast control boundary token', /--control-border:\s*#[0-9a-f]{6}/i],
]) if (!pattern.test(responsiveCss)) fail(responsiveCssFile, `missing responsive contract: ${label}`);
Expand Down Expand Up @@ -267,6 +271,15 @@ if (!/workspaceScroll\.tabIndex\s*=\s*0/.test(appSource) ||
!/workspaceScroll\.setAttribute\(['"]aria-labelledby['"],\s*['"]workspaceTitle['"]\)/.test(appSource)) {
fail(join(site, 'app.js'), 'the evidence scroller is not keyboard focusable and labelled');
}
if (!/function syncWorkspaceReading\(\)/.test(appSource) ||
!/workspaceBack\.onclick\s*=\s*leaveWorkspaceReading/.test(appSource) ||
!/workspaceRead\.setAttribute\(['"]aria-expanded['"]/.test(appSource)) {
fail(join(site, 'app.js'), 'full-screen reading mode lacks a persistent, stateful return to the map');
}
if (!/panel\.scrollTop\s*=\s*0/.test(appSource) ||
!/new ResizeObserver\(syncWorkspaceHeadHeight\)\.observe\(workspaceHead\)/.test(appSource)) {
fail(join(site, 'app.js'), 'detail reading does not start at the top or respect the live navigation height');
}
const siteSource = readFileSync(join(site, 'site.js'), 'utf8');
if (!/function restoreDeepLink\(\)[\s\S]*?target\.scrollIntoView\(\{ block: 'start' \}\)[\s\S]*?new ResizeObserver\(align\)/.test(siteSource)) {
fail(join(site, 'site.js'), 'late data layout can displace direct section links');
Expand Down
78 changes: 77 additions & 1 deletion site/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ if (themeControl) workspaceUtility.append(themeControl);
workspaceHead.append(workspaceUtility);
if (siteNav) workspaceHead.append(siteNav);

// Detail reading occupies the whole evidence surface below the persistent
// project navigation. Measure that navigation instead of duplicating its height
// in breakpoint-specific CSS; safe-area insets and translated labels can change it.
const syncWorkspaceHeadHeight = () => {
workspace.style.setProperty('--workspace-head-h', `${workspaceHead.offsetHeight}px`);
};
syncWorkspaceHeadHeight();
new ResizeObserver(syncWorkspaceHeadHeight).observe(workspaceHead);

const workspaceScroll = document.createElement('div');
workspaceScroll.id = 'workspaceScroll';
workspaceScroll.tabIndex = 0;
Expand Down Expand Up @@ -77,6 +86,60 @@ for (const [side, arrow] of [['start', '\u2039'], ['end', '\u203a']]) {
modeRail.append(cue);
}

// The map remains the working surface; prose can become a reading surface on
// demand. The same full-screen mode is used for legal review, selected features
// and the first-visit brief, so users learn one way in and one way back.
let manualReading = false;
const workspaceBack = document.createElement('button');
workspaceBack.type = 'button';
workspaceBack.id = 'workspaceBack';
workspaceBack.hidden = true;
workspaceBack.textContent = `\u2190 ${T('m.backToMap')}`;
workspaceBack.setAttribute('aria-label', T('m.backToMapAria'));
workspaceUtility.insertBefore(workspaceBack, languageSwitch || themeControl || null);

const workspaceRead = document.createElement('button');
workspaceRead.type = 'button';
workspaceRead.id = 'workspaceRead';
workspaceRead.textContent = T('m.readEvidence');
workspaceRead.setAttribute('aria-label', T('m.readEvidenceAria'));
workspaceRead.setAttribute('aria-expanded', 'false');
document.getElementById('dataViewOpen')?.before(workspaceRead);

function syncWorkspaceReading() {
const active = manualReading || document.body.classList.contains('readingLegal') ||
document.body.classList.contains('readingDetail') ||
document.body.classList.contains('readingBrief');
document.body.classList.toggle('workspaceReading', active);
workspaceBack.hidden = !active;
workspaceRead.setAttribute('aria-expanded', String(active));
}

function leaveWorkspaceReading() {
manualReading = false;
if (legalAlertToggle?.getAttribute('aria-expanded') === 'true') {
legalAlertToggle.setAttribute('aria-expanded', 'false');
legalAlertBody.hidden = true;
}
document.body.classList.remove('readingLegal');
if (!panel.hidden) closePanel(false);
const brief = document.getElementById('intro');
if (brief?.open) document.getElementById('introClose')?.click();
document.body.classList.remove('readingDetail', 'readingBrief');
syncWorkspaceReading();
cv.focus({ preventScroll: true });
}

workspaceRead.onclick = () => {
manualReading = true;
syncWorkspaceReading();
requestAnimationFrame(() => {
workspaceScroll.scrollTo({ top: 0 });
workspaceScroll.focus({ preventScroll: true });
});
};
workspaceBack.onclick = leaveWorkspaceReading;

const ENDPOINT = 'https://lindas.admin.ch/query';

/* ---- the palette -----------------------------------------------------------
Expand Down Expand Up @@ -831,6 +894,9 @@ legalAlertToggle?.addEventListener('click', () => {
const open = legalAlertToggle.getAttribute('aria-expanded') === 'true';
legalAlertToggle.setAttribute('aria-expanded', String(!open));
legalAlertBody.hidden = open;
document.body.classList.toggle('readingLegal', !open);
syncWorkspaceReading();
if (!open) requestAnimationFrame(() => legalAlertRoot.scrollIntoView({ block: 'nearest' }));
});

/* ===========================================================================
Expand Down Expand Up @@ -1802,11 +1868,16 @@ function tip(mx, my) {
const panel = document.getElementById('panel');
let panelReturnFocus = null;
function revealPanel(moveFocus) {
panel.scrollTop = 0;
panel.hidden = false;
if (moveFocus) requestAnimationFrame(() => panel.focus({ preventScroll: true }));
document.body.classList.add('readingDetail');
syncWorkspaceReading();
requestAnimationFrame(() => panel.focus({ preventScroll: true }));
}
function closePanel(returnFocus = true) {
panel.hidden = true;
document.body.classList.remove('readingDetail');
syncWorkspaceReading();
selected = null;
dirty = true;
const target = panelReturnFocus;
Expand Down Expand Up @@ -2358,6 +2429,7 @@ dataNext.onclick = () => { dataPage++; renderDataView(); };
window.addEventListener('keydown', e => {
if (e.key !== 'Escape') return;
if (!panel.hidden) closePanel();
else if (document.body.classList.contains('workspaceReading')) leaveWorkspaceReading();
});

/* ===========================================================================
Expand Down Expand Up @@ -3861,11 +3933,15 @@ function setLiveOnly(v) {
const show = () => {
if (!dialog.open) dialog.show();
dialog.scrollTop = 0;
document.body.classList.add('readingBrief');
syncWorkspaceReading();
document.getElementById('introClose').focus({ preventScroll: true });
};
const close = () => {
try { localStorage.setItem(KEY, '1'); } catch (e) { /* private mode */ }
if (dialog.open) dialog.close();
document.body.classList.remove('readingBrief');
syncWorkspaceReading();
cv.focus({ preventScroll: true });
};
if (open) open.onclick = show;
Expand Down
2 changes: 1 addition & 1 deletion site/data/provenance.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions site/de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="../fonts.css?v=20260821">
<link rel="stylesheet" href="../tokens.css?v=20260822">
<link rel="stylesheet" href="../style.css?v=20260822g">
<link rel="stylesheet" href="../style.css?v=20260822h">
<script src="../i18n.js?v=20260821"></script>
<script src="../i18n-data.js?v=20260821"></script>
<script src="../i18n-map.js?v=20260822"></script>
<script src="../i18n-map.js?v=20260822b"></script>
<script src="../theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -407,6 +407,6 @@ <h2 id="introTitle">Dem Wasser folgen. Seine Wege schützen.</h2>
<script src="../fmt.js?v=20260822"></script>
<script src="../gschg31.js?v=20260821"></script>
<script src="../legal-alerts.js?v=20260822"></script>
<script src="../app.js?v=20260822g"></script>
<script src="../app.js?v=20260822h"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions site/en/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="../fonts.css?v=20260821">
<link rel="stylesheet" href="../tokens.css?v=20260822">
<link rel="stylesheet" href="../style.css?v=20260822g">
<link rel="stylesheet" href="../style.css?v=20260822h">
<script src="../i18n.js?v=20260821"></script>
<script src="../i18n-data.js?v=20260821"></script>
<script src="../i18n-map.js?v=20260822"></script>
<script src="../i18n-map.js?v=20260822b"></script>
<script src="../theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -466,6 +466,6 @@ <h2 id="introTitle">Follow the water. Protect its pathways.</h2>
<script src="../fmt.js?v=20260822"></script>
<script src="../gschg31.js?v=20260821"></script>
<script src="../legal-alerts.js?v=20260822"></script>
<script src="../app.js?v=20260822g"></script>
<script src="../app.js?v=20260822h"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions site/fr/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="../fonts.css?v=20260821">
<link rel="stylesheet" href="../tokens.css?v=20260822">
<link rel="stylesheet" href="../style.css?v=20260822g">
<link rel="stylesheet" href="../style.css?v=20260822h">
<script src="../i18n.js?v=20260821"></script>
<script src="../i18n-data.js?v=20260821"></script>
<script src="../i18n-map.js?v=20260822"></script>
<script src="../i18n-map.js?v=20260822b"></script>
<script src="../theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -407,6 +407,6 @@ <h2 id="introTitle">Suivre l’eau. Protéger ses voies.</h2>
<script src="../fmt.js?v=20260822"></script>
<script src="../gschg31.js?v=20260821"></script>
<script src="../legal-alerts.js?v=20260822"></script>
<script src="../app.js?v=20260822g"></script>
<script src="../app.js?v=20260822h"></script>
</body>
</html>
12 changes: 12 additions & 0 deletions site/i18n-map.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="fonts.css?v=20260821">
<link rel="stylesheet" href="tokens.css?v=20260822">
<link rel="stylesheet" href="style.css?v=20260822g">
<link rel="stylesheet" href="style.css?v=20260822h">
<script src="i18n.js?v=20260821"></script>
<script src="i18n-data.js?v=20260821"></script>
<script src="i18n-map.js?v=20260822"></script>
<script src="i18n-map.js?v=20260822b"></script>
<script src="theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -407,6 +407,6 @@ <h2 id="introTitle">Dem Wasser folgen. Seine Wege schützen.</h2>
<script src="fmt.js?v=20260822"></script>
<script src="gschg31.js?v=20260821"></script>
<script src="legal-alerts.js?v=20260822"></script>
<script src="app.js?v=20260822g"></script>
<script src="app.js?v=20260822h"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions site/it/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="../fonts.css?v=20260821">
<link rel="stylesheet" href="../tokens.css?v=20260822">
<link rel="stylesheet" href="../style.css?v=20260822g">
<link rel="stylesheet" href="../style.css?v=20260822h">
<script src="../i18n.js?v=20260821"></script>
<script src="../i18n-data.js?v=20260821"></script>
<script src="../i18n-map.js?v=20260822"></script>
<script src="../i18n-map.js?v=20260822b"></script>
<script src="../theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -407,6 +407,6 @@ <h2 id="introTitle">Seguire l’acqua. Proteggere i suoi percorsi.</h2>
<script src="../fmt.js?v=20260822"></script>
<script src="../gschg31.js?v=20260821"></script>
<script src="../legal-alerts.js?v=20260822"></script>
<script src="../app.js?v=20260822g"></script>
<script src="../app.js?v=20260822h"></script>
</body>
</html>
6 changes: 3 additions & 3 deletions site/rm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="../fonts.css?v=20260821">
<link rel="stylesheet" href="../tokens.css?v=20260822">
<link rel="stylesheet" href="../style.css?v=20260822g">
<link rel="stylesheet" href="../style.css?v=20260822h">
<script src="../i18n.js?v=20260821"></script>
<script src="../i18n-data.js?v=20260821"></script>
<script src="../i18n-map.js?v=20260822"></script>
<script src="../i18n-map.js?v=20260822b"></script>
<script src="../theme.js?v=20260821"></script>
</head>
<body class="viz-root" data-layer="flow">
Expand Down Expand Up @@ -407,6 +407,6 @@ <h2 id="introTitle">Suandar l’aua. Proteger sias vias.</h2>
<script src="../fmt.js?v=20260822"></script>
<script src="../gschg31.js?v=20260821"></script>
<script src="../legal-alerts.js?v=20260822"></script>
<script src="../app.js?v=20260822g"></script>
<script src="../app.js?v=20260822h"></script>
</body>
</html>
Loading