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
15 changes: 8 additions & 7 deletions build/pages/index.en.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<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=20260822b">
<link rel="stylesheet" href="style.css?v=20260822c">
<script src="i18n.js?v=20260821"></script>
<script src="i18n-data.js?v=20260821"></script>
<script src="i18n-map.js?v=20260822"></script>
Expand Down Expand Up @@ -383,12 +383,13 @@ <h2 id="dataViewTitle">Explore this layer as data</h2>
<span class="langs introLangs" data-langswitch></span>
</div>
<h2 id="introTitle">Follow the water. Protect its pathways.</h2>
<p class="introLead" id="introLead">Trace water through Switzerland—from ice and groundwater to
rivers, storage, use, return and the border—and identify the law protecting each essential
pathway. The aim is to protect wetlands and enable legal action when those protections fail.
This first release focuses on surface water. Every figure states its source, date and evidence class.</p>
<p class="introLead" id="introLead">Riverflow follows water through Switzerland—from ice and
groundwater to rivers, storage, use and return. It shows what is measured, what is estimated and
which law protects each essential pathway. The aim: protect wetlands and enforce the law when
necessary. This first release focuses on surface water. Every figure names its source, date and
evidence class.</p>
<div class="introActions">
<button type="button" id="introEnter" autofocus>Explore the map</button>
<button type="button" id="introEnter">Explore the map</button>
<a href="method.html">How the evidence works</a>
</div>
<figure class="cycleViz" aria-labelledby="cycleCaption">
Expand Down Expand Up @@ -441,6 +442,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="app.js?v=20260822"></script>
<script src="app.js?v=20260822b"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion build/pages/updates.json
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@
"<b>The inventories do not age together.</b> The amphibian inventory was revised in May 2026. The alluvial-zone and mire-landscape inventories still state November 2017. <a href=\"sources.html#table\">See every date</a>.": {"de":"<b>Die Inventare altern nicht gemeinsam.</b> Das Amphibieninventar wurde im Mai 2026 revidiert. Das Auenschutz- und das Moorlandschaftsinventar nennen weiterhin November 2017. <a href=\"sources.html#table\">Alle Daten ansehen</a>.","fr":"<b>Les inventaires ne vieillissent pas ensemble.</b> L’inventaire des batraciens a été révisé en mai 2026. Ceux des zones alluviales et des sites marécageux indiquent toujours novembre 2017. <a href=\"sources.html#table\">Voir toutes les dates</a>.","it":"<b>Gli inventari non invecchiano insieme.</b> L’inventario degli anfibi è stato rivisto nel maggio 2026. Quelli delle zone golenali e delle zone palustri indicano ancora novembre 2017. <a href=\"sources.html#table\">Vedere tutte le date</a>.","rm":"<b>Ils inventaris na vegneschan betg ensemen.</b> L’inventari dals amfibis è vegnì revedì il matg 2026. Ils inventaris da las zonas alluvialas e da las cuntradas da palì inditgeschan anc november 2017. <a href=\"sources.html#table\">Vesair tut las datas</a>."},
"<b>Three overlays arrive as images.</b> This map cannot query or verify the groundwater bodies, protection zones or catchments. Headwaters are the exception: they are drawn from this map&rsquo;s network.": {"de":"<b>Drei Überlagerungen kommen als Bilder an.</b> Diese Karte kann Grundwasserkörper, Schutzzonen und Einzugsgebiete weder abfragen noch prüfen. Die Oberläufe sind die Ausnahme: Sie stammen aus dem Flussnetz dieser Karte.","fr":"<b>Trois superpositions arrivent sous forme d’images.</b> La carte ne peut ni interroger ni vérifier les masses d’eau souterraine, zones de protection et bassins versants. Les têtes de bassin font exception : elles proviennent du réseau de cette carte.","it":"<b>Tre sovrapposizioni arrivano come immagini.</b> La carta non può interrogare o verificare corpi idrici sotterranei, zone di protezione e bacini. Fanno eccezione i tratti di testa, ricavati dalla rete della carta.","rm":"<b>Trais surposiziuns arrivan sco maletgs.</b> La charta na po ni dumandar ni verifitgar ils corps d’aua sutterrana, las zonas da protecziun ed ils intschess. Ils curs superiurs èn l’excepziun: els derivan da la rait da questa charta."},
"<b>A headwater is not a spring.</b> It is the top of the drawn river network, clipped at 5&nbsp;km&#178; of upstream area. At closer zoom, swissNAMES3D adds 86 named springs and 157 named waterfalls—not a complete national inventory.": {"de":"<b>Ein Oberlauf ist keine Quelle.</b> Er ist das obere Ende des gezeichneten Flussnetzes, begrenzt auf 5&nbsp;km&#178; Einzugsfläche. Bei näherem Zoom ergänzt swissNAMES3D 86 benannte Quellen und 157 benannte Wasserfälle – kein vollständiges Landesinventar.","fr":"<b>Une tête de bassin n’est pas une source.</b> C’est le sommet du réseau fluvial dessiné, limité à 5&nbsp;km&#178; de bassin amont. À plus grande échelle, swissNAMES3D ajoute 86 sources et 157 cascades nommées — ce n’est pas un inventaire national complet.","it":"<b>Un tratto di testa non è una sorgente.</b> È l’estremità superiore della rete fluviale disegnata, limitata a 5&nbsp;km&#178; di bacino a monte. A maggior ingrandimento swissNAMES3D aggiunge 86 sorgenti e 157 cascate nominate, non un inventario nazionale completo.","rm":"<b>In curs superiur n’è betg ina funtauna.</b> El è il punct il pli aut da la rait da flums dissegnada, limità a 5&nbsp;km&#178; d’intschess amunt. Cun dapli zoom agiunta swissNAMES3D 86 funtaunas e 157 cascadas numnadas – betg in inventari naziunal cumplet."},
"Trace water through Switzerland—from ice and groundwater to rivers, storage, use, return and the border—and identify the law protecting each essential pathway. The aim is to protect wetlands and enable legal action when those protections fail. This first release focuses on surface water. Every figure states its source, date and evidence class.": {"de":"Das Projekt folgt dem Wasser durch die Schweiz – von Eis und Grundwasser über Flüsse, Speicherung, Nutzung und Rücklauf bis zur Grenze – und zeigt, welches Recht jeden wesentlichen Weg schützt. Ziel ist es, Feuchtgebiete zu schützen und rechtliche Schritte zu ermöglichen, wenn dieser Schutz nicht durchgesetzt wird. Diese erste Ausgabe konzentriert sich auf Oberflächengewässer. Jede Zahl nennt Quelle, Datum und Beweisklasse.","fr":"Suivre l’eau à travers la Suisse — de la glace et des eaux souterraines aux cours d’eau, au stockage, aux usages, aux retours et à la frontière — et identifier le droit qui protège chaque voie essentielle. Le but est de protéger les zones humides et de permettre une action juridique lorsque ces protections échouent. Cette première version porte sur les eaux superficielles. Chaque chiffre indique sa source, sa date et sa classe de preuve.","it":"Seguire l’acqua attraverso la Svizzera — dal ghiaccio e dalle acque sotterranee ai corsi d’acqua, allo stoccaggio, all’uso, alla restituzione e al confine — e identificare il diritto che protegge ogni via essenziale. L’obiettivo è proteggere le zone umide e rendere possibile l’azione legale quando tali protezioni falliscono. Questa prima edizione si concentra sulle acque superficiali. Ogni dato indica fonte, data e classe di prova.","rm":"Suandar l’aua tras la Svizra – dal glatsch e da l’aua sutterrana als flums, a l’accumulaziun, utilisaziun, return e cunfin – ed identifitgar il dretg che protegia mintga via essenziala. La finamira è da proteger las zonas umidas e da pussibilitar pass giuridics sche quella protecziun n’effectuescha betg. Questa emprima ediziun sa concentrescha sin las auas a la surfatscha. Mintga cifra inditgescha funtauna, data e classa da cumprova."},
"Riverflow follows water through Switzerland—from ice and groundwater to rivers, storage, use and return. It shows what is measured, what is estimated and which law protects each essential pathway. The aim: protect wetlands and enforce the law when necessary. This first release focuses on surface water. Every figure names its source, date and evidence class.": {"de":"Riverflow folgt dem Wasser durch die Schweiz – von Eis und Grundwasser über Flüsse, Speicher und Nutzung bis zum Rücklauf. Es zeigt, was gemessen ist, was geschätzt wird und welches Recht jeden wesentlichen Weg schützt. Das Ziel: Feuchtgebiete schützen und das Recht durchsetzen, wenn nötig. Diese erste Ausgabe konzentriert sich auf Oberflächengewässer. Jede Zahl nennt Quelle, Datum und Beweisklasse.","fr":"Riverflow suit l’eau à travers la Suisse — de la glace et des eaux souterraines aux cours d’eau, au stockage, à l’usage et au retour. Il distingue ce qui est mesuré de ce qui est estimé et indique le droit qui protège chaque voie essentielle. L’objectif : protéger les zones humides et, si nécessaire, faire appliquer le droit. Cette première édition porte sur les eaux superficielles. Chaque chiffre indique sa source, sa date et sa classe de preuve.","it":"Riverflow segue l’acqua attraverso la Svizzera — dal ghiaccio e dalle acque sotterranee ai corsi d’acqua, allo stoccaggio, all’uso e alla restituzione. Mostra ciò che è misurato, ciò che è stimato e quale diritto protegge ogni via essenziale. L’obiettivo: proteggere le zone umide e far rispettare il diritto quando necessario. Questa prima edizione si concentra sulle acque superficiali. Ogni dato indica fonte, data e classe di prova.","rm":"Riverflow suonda l’aua tras la Svizra – dal glatsch e da l’aua sutterrana als flums, a l’accumulaziun, a l’utilisaziun ed al return. El mussa tge ch’è mesirà, tge ch’è stimà e tge dretg che protegia mintga via essenziala. La finamira: proteger las zonas umidas ed exequir il dretg sche necessari. Questa emprima ediziun sa concentrescha sin las auas a la surfatscha. Mintga cifra inditgescha funtauna, data e classa da cumprova."},
"Mountain precipitation becomes ice, groundwater, springs, rivers and wetlands. Water is stored, used, returned and evaporated.": {"de":"Niederschlag im Gebirge wird zu Eis, Grundwasser, Quellen, Flüssen und Feuchtgebieten. Wasser wird gespeichert, genutzt, zurückgeführt und verdunstet.","fr":"Les précipitations en montagne deviennent glace, eaux souterraines, sources, cours d’eau et zones humides. L’eau est stockée, utilisée, restituée et évaporée.","it":"Le precipitazioni in montagna diventano ghiaccio, acque sotterranee, sorgenti, corsi d’acqua e zone umide. L’acqua viene accumulata, usata, restituita ed evapora.","rm":"La precipitaziun en muntogna daventa glatsch, aua sutterrana, funtaunas, flums e zonas umidas. L’aua vegn accumulada, utilisada, restituida ed evapurescha."},
"<b>Springs &amp; groundwater</b><span>partly mapped</span>": {"de":"<b>Quellen &amp; Grundwasser</b><span>teilweise kartiert</span>","fr":"<b>Sources et eaux souterraines</b><span>partiellement cartographiées</span>","it":"<b>Sorgenti e acque sotterranee</b><span>parzialmente cartografate</span>","rm":"<b>Funtaunas ed aua sutterrana</b><span>per part sin la charta</span>"},
"<strong>2011&ndash;2024</strong><span>Federal water-quality results</span>": {"de":"<strong>2011&ndash;2024</strong><span>Bundesmessdaten zur Wasserqualität</span>","fr":"<strong>2011&ndash;2024</strong><span>Résultats fédéraux sur la qualité de l’eau</span>","it":"<strong>2011&ndash;2024</strong><span>Risultati federali sulla qualità dell’acqua</span>","rm":"<strong>2011&ndash;2024</strong><span>Resultats federals da la qualitad da l’aua</span>"},
Expand Down
30 changes: 26 additions & 4 deletions scripts/verify-site.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,17 @@ const responsiveCssFile = join(site, 'style.css');
const responsiveCss = readFileSync(join(site, 'tokens.css'), 'utf8') + '\n' + readFileSync(responsiveCssFile, 'utf8');
for (const [label, pattern] of [
['safe-area top inset', /--safe-t:\s*env\(safe-area-inset-top/],
['44 px mobile layer controls', /#modes button\s*\{[^}]*min-height:\s*44px/s],
['44 px mobile layer controls', /#workspace #modes button\s*\{[^}]*min-height:\s*44px/s],
['44 px mobile legend controls', /\.controls label\s*\{\s*min-height:\s*44px/],
['dynamic mobile sheet height', /max-height:\s*76dvh/],
['dynamic mobile dialog height', /max-height:\s*calc\(100dvh - 12px\)/],
['large landing language targets', /#intro \.introLangs \[lang\][^{]*\{[^}]*min-width:\s*40px;[^}]*min-height:\s*44px/s],
['contained intermediate mode rail', /@media \(min-width:\s*701px\) and \(max-width:\s*1340px\)[\s\S]*?#modes\s*\{[^}]*overflow-x:\s*auto/],
['collision-free wide mode rail', /@media \(min-width:\s*1900px\)[\s\S]*?#modes\s*\{[^}]*left:\s*calc\(var\(--pad\) \+ 484px\)/],
['persistent evidence workspace', /#workspace\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;[^}]*width:\s*var\(--workspace-w\)/s],
['unobstructed desktop map surface', /#map, #flow\s*\{[^}]*left:\s*var\(--workspace-w\);[^}]*width:\s*calc\(100vw - var\(--workspace-w\)\);[^}]*height:\s*100dvh/s],
['independently scrolling evidence', /#workspace #legend\s*\{[^}]*flex:\s*1 1 auto;[^}]*overflow-y:\s*auto/s],
['stacked portrait workspace', /@media \(max-width:\s*900px\) and \(orientation:\s*portrait\)[\s\S]*?#workspace\s*\{[^}]*height:\s*var\(--workspace-h\)[\s\S]*?#map, #flow\s*\{[^}]*width:\s*100vw;[^}]*height:\s*calc\(100dvh - var\(--workspace-h\)\)/s],
['compact short-landscape rail', /@media \(max-height:\s*560px\) and \(orientation:\s*landscape\)[\s\S]*?#workspace #modes\s*\{[^}]*overflow-x:\s*auto/s],
['sidebar project brief', /#workspace #intro\s*\{[^}]*position:\s*absolute;[^}]*inset:\s*0;[^}]*height:\s*100%/s],
['sidebar map readout', /#workspace #tooltip\s*\{[^}]*position:\s*static;[^}]*border-bottom:/s],
['high-contrast control boundary token', /--control-border:\s*#[0-9a-f]{6}/i],
]) if (!pattern.test(responsiveCss)) fail(responsiveCssFile, `missing responsive contract: ${label}`);
const appSource = readFileSync(join(site, 'app.js'), 'utf8');
Expand All @@ -179,6 +183,24 @@ if (!/window\.visualViewport\?\.addEventListener\(['"]resize['"]/.test(appSource
if (!/modeNav\.addEventListener\(['"]wheel['"]/.test(appSource)) {
fail(join(site, 'app.js'), 'intermediate mode rail has no practical mouse-wheel navigation');
}
if (!/workspace\.append\(el\)/.test(appSource) || !/dialog\.show\(\)/.test(appSource) || /dialog\.showModal\(\)/.test(appSource)) {
fail(join(site, 'app.js'), 'project brief must occupy the evidence workspace without covering the map');
}
const workspaceComposition = /for \(const id of \[([^\]]+)\]\)/.exec(appSource.slice(0, 3500))?.[1] ?? '';
for (const id of ['titlebar', 'modes', 'mapControls', 'tooltip', 'legend', 'ribbon', 'panel', 'intro']) {
if (!new RegExp(`['"]${id}['"]`).test(workspaceComposition)) {
fail(join(site, 'app.js'), `${id} is not composed into the evidence workspace`);
}
}
if (/tt\.style\.(?:left|top)\s*=/.test(appSource)) {
fail(join(site, 'app.js'), 'map readout must live in the evidence workspace instead of floating over geography');
}
if (!/function canvasPoint\(e\)/.test(appSource) || !/e\.clientX - box\.left/.test(appSource)) {
fail(join(site, 'app.js'), 'pointer coordinates are not translated into the offset canvas');
}
if (!/function fitBox\(\)\s*\{[\s\S]*?return \{ t: 0, b: 0 \};[\s\S]*?\n\}/.test(appSource)) {
fail(join(site, 'app.js'), 'map fit still reserves space for controls that no longer overlay the canvas');
}
const initialLoad = /async function load\(\)\s*\{([\s\S]*?)\n\}\n\n\/\/ The ice/.exec(appSource)?.[1] ?? '';
for (const name of ['loadIce', 'loadUsers', 'loadReservoirs', 'loadResidual', 'loadWetlands', 'loadCantons']) {
if (new RegExp('\\b' + name + '\\s*\\(').test(initialLoad)) fail(join(site, 'app.js'), name + ' is loaded eagerly instead of on layer request');
Expand Down
Loading