refactor(marketplace): UI-Verbesserungen, MarketplaceDeckStack, Explore-Icons

- DeckListGrid: überarbeitetes Layout
- EmptyState + SkeletonGrid: aufgeräumt
- Neuer MarketplaceDeckStack für Marketplace-Karten-Darstellung
- Explore: Icons (Fire, Star, MagnifyingGlass, Books) + Header-Cleanup
- me/forks + me/subscribed: kleinere Korrekturen
- docs/deck_ideas: initiale Ideen-Sammlung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-05-10 16:00:11 +02:00
parent 1f1abf3c4f
commit 0c68186563
8 changed files with 451 additions and 101 deletions

View file

@ -1,9 +1,6 @@
<script lang="ts"> <script lang="ts">
import type { DeckListEntry } from '$lib/api/marketplace.ts'; import type { DeckListEntry } from '$lib/api/marketplace.ts';
import type { DeckCategoryId } from '@cards/domain'; import MarketplaceDeckStack from './MarketplaceDeckStack.svelte';
import { DECK_CATEGORY_IDS } from '@cards/domain';
import AuthorBadge from './AuthorBadge.svelte';
import DeckCategoryIcon from '$lib/components/DeckCategoryIcon.svelte';
interface Props { interface Props {
items: DeckListEntry[]; items: DeckListEntry[];
@ -11,83 +8,82 @@
} }
const { items, emptyMessage = 'Noch keine Decks gefunden.' }: Props = $props(); const { items, emptyMessage = 'Noch keine Decks gefunden.' }: Props = $props();
function isValidCategory(c: string | null): c is DeckCategoryId {
return c !== null && (DECK_CATEGORY_IDS as readonly string[]).includes(c);
}
function languageLabel(code: string | null): string {
if (!code) return '';
const map: Record<string, string> = { de: 'Deutsch', en: 'English', es: 'Español', fr: 'Français' };
return map[code] ?? code.toUpperCase();
}
</script> </script>
{#if items.length === 0} {#if items.length === 0}
<p class="rounded-lg border border-dashed border-[hsl(var(--color-border))] p-8 text-center text-sm text-[hsl(var(--color-muted-foreground))]"> <p class="empty">
{emptyMessage} {emptyMessage}
</p> </p>
{:else} {:else}
<ul class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"> <ul class="deck-row" aria-label="Decks">
{#each items as deck (deck.slug)} {#each items as deck (deck.slug)}
<li <li class="deck-item">
class="group relative rounded-lg border border-[hsl(var(--color-border))] bg-[hsl(var(--color-card))] p-4 transition-colors hover:border-[hsl(var(--color-primary))]" <MarketplaceDeckStack {deck} />
>
<a href="/d/{deck.slug}" class="block">
<div class="flex items-start justify-between gap-2">
<h3 class="truncate font-medium">{deck.title}</h3>
<div class="flex shrink-0 items-center gap-1.5">
{#if isValidCategory(deck.category)}
<span class="text-[hsl(var(--color-muted-foreground))]" aria-hidden="true">
<DeckCategoryIcon category={deck.category} size={16} weight="duotone" />
</span>
{/if}
{#if deck.is_featured}
<span
class="rounded-full bg-[hsl(var(--color-primary))]/15 px-2 py-0.5 text-[10px] font-medium text-[hsl(var(--color-primary))]"
title="Editorial Pick"
>
★ Featured
</span>
{/if}
</div>
</div>
{#if deck.description}
<p
class="mt-1 line-clamp-2 text-xs text-[hsl(var(--color-muted-foreground))]"
>
{deck.description}
</p>
{/if}
<div class="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-[hsl(var(--color-muted-foreground))]">
<AuthorBadge
slug={deck.owner.slug}
displayName={deck.owner.display_name}
verifiedMana={deck.owner.verified_mana}
verifiedCommunity={deck.owner.verified_community}
size="sm"
/>
<span>·</span>
<span title="Karten">{deck.card_count} 🃏</span>
<span>·</span>
<span title="Stars">{deck.star_count}</span>
{#if deck.subscriber_count > 0}
<span>·</span>
<span title="Subscribers">{deck.subscriber_count} ↩︎</span>
{/if}
{#if deck.language}
<span>·</span>
<span class="uppercase">{languageLabel(deck.language)}</span>
{/if}
{#if deck.price_credits > 0}
<span>·</span>
<span class="font-medium text-[hsl(var(--color-primary))]">
{deck.price_credits} Credits
</span>
{/if}
</div>
</a>
</li> </li>
{/each} {/each}
</ul> </ul>
{/if} {/if}
<style>
.empty {
border: 1px dashed hsl(var(--color-border));
border-radius: 0.75rem;
padding: 2rem;
text-align: center;
font-size: 0.875rem;
color: hsl(var(--color-muted-foreground));
}
.deck-row {
list-style: none;
margin: 0;
padding-block: 0 1rem;
display: flex;
flex-direction: row;
gap: 1rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
/* snap-padding entspricht dem ::before-Spacer */
scroll-padding-inline-start: max(1rem, calc((100dvw - 72rem) / 2 + 1rem));
scrollbar-width: thin;
scrollbar-color: hsl(var(--color-border)) transparent;
/* Full-bleed: break out of main's max-width + padding */
width: 100dvw;
margin-left: calc(50% - 50dvw);
}
/* Flex-Spacer am Anfang schafft zuverlässig den initialen Einzug —
padding-inline-start auf scroll-containern ist browser-inkonsistent */
.deck-row::before {
content: '';
flex-shrink: 0;
width: max(1rem, calc((100dvw - 72rem) / 2 + 1rem));
}
/* Trailing spacer damit letzte Karte nicht am rechten Rand klebt */
.deck-row::after {
content: '';
flex-shrink: 0;
width: max(1rem, calc((100dvw - 72rem) / 2 + 1rem));
}
.deck-row::-webkit-scrollbar {
height: 4px;
}
.deck-row::-webkit-scrollbar-track {
background: transparent;
}
.deck-row::-webkit-scrollbar-thumb {
background: hsl(var(--color-border));
border-radius: 9999px;
}
.deck-item {
flex: 0 0 auto;
width: 16rem;
scroll-snap-align: start;
}
</style>

View file

@ -1,20 +1,24 @@
<script lang="ts"> <script lang="ts">
import type { Component } from 'svelte';
interface Props { interface Props {
icon?: string; icon?: Component;
title: string; title: string;
description?: string; description?: string;
ctaHref?: string; ctaHref?: string;
ctaLabel?: string; ctaLabel?: string;
} }
const { icon, title, description, ctaHref, ctaLabel }: Props = $props(); const { icon: IconComponent, title, description, ctaHref, ctaLabel }: Props = $props();
</script> </script>
<div <div
class="rounded-lg border border-dashed border-[hsl(var(--color-border))] bg-[hsl(var(--color-card))]/40 p-10 text-center" class="rounded-lg border border-dashed border-[hsl(var(--color-border))] bg-[hsl(var(--color-card))]/40 p-10 text-center"
> >
{#if icon} {#if IconComponent}
<div class="mx-auto mb-3 text-4xl" aria-hidden="true">{icon}</div> <div class="icon-wrap" aria-hidden="true">
<IconComponent size={40} weight="duotone" />
</div>
{/if} {/if}
<h3 class="text-lg font-medium">{title}</h3> <h3 class="text-lg font-medium">{title}</h3>
{#if description} {#if description}
@ -31,3 +35,12 @@
</a> </a>
{/if} {/if}
</div> </div>
<style>
.icon-wrap {
display: flex;
justify-content: center;
margin-bottom: 0.75rem;
color: hsl(var(--color-muted-foreground));
}
</style>

View file

@ -0,0 +1,183 @@
<script lang="ts">
import type { DeckListEntry } from '$lib/api/marketplace.ts';
import type { DeckCategoryId } from '@cards/domain';
import { DECK_CATEGORY_IDS } from '@cards/domain';
import { stackLayers, deterministicRandoms } from '$lib/utils/deck-tilt';
import { Star } from '@mana/shared-icons';
import CardSurface from '$lib/components/CardSurface.svelte';
import DeckCategoryIcon from '$lib/components/DeckCategoryIcon.svelte';
interface Props {
deck: DeckListEntry;
}
let { deck }: Props = $props();
const layers = $derived(stackLayers(deck.slug, 3));
function isValidCategory(c: string | null): c is DeckCategoryId {
return c !== null && (DECK_CATEGORY_IDS as readonly string[]).includes(c);
}
const CATEGORY_COLORS: Record<DeckCategoryId, string> = {
language: '#3B82F6',
medicine: '#EF4444',
science: '#22C55E',
math: '#6366F1',
history: '#F59E0B',
law: '#64748B',
technology: '#06B6D4',
arts: '#A855F7',
music: '#EC4899',
sport: '#16A34A',
other: '#9CA3AF',
};
// Fallback: deterministisch aus slug-Hash, aus einem freundlichen Palette
const FALLBACK_PALETTE = ['#3B82F6','#22C55E','#F59E0B','#A855F7','#06B6D4','#EC4899','#EF4444'];
const accentColor = $derived((): string => {
if (isValidCategory(deck.category)) return CATEGORY_COLORS[deck.category];
const [r] = deterministicRandoms(deck.slug, 1);
return FALLBACK_PALETTE[Math.floor(r * FALLBACK_PALETTE.length)];
});
</script>
<div class="stack-wrap">
{#each layers as layer, i (i)}
<div
class="layer"
style:transform="translate({layer.dx}px, {layer.dy}px) rotate({layer.tilt}deg)"
aria-hidden="true"
></div>
{/each}
<CardSurface
size="md"
as="a"
href="/d/{deck.slug}"
ariaLabel="{deck.title} · {deck.card_count} Karten"
colorAccent={accentColor()}
class="cover"
>
<div class="cover-inner">
<div class="cover-corner" aria-hidden="true">
{#if isValidCategory(deck.category)}
<DeckCategoryIcon category={deck.category} size={20} color={accentColor()} weight="duotone" />
{/if}
{#if deck.is_featured}
<span class="featured-badge" title="Editorial Pick">
<Star size={14} weight="fill" />
</span>
{/if}
</div>
<div class="cover-body">
<h2 class="cover-title">{deck.title}</h2>
{#if deck.description}
<p class="cover-desc">{deck.description}</p>
{/if}
</div>
<div class="cover-meta">
<span class="meta-count">{deck.card_count} Karten</span>
{#if deck.star_count > 0}
<span class="meta-stars">
<Star size={11} weight="fill" />{deck.star_count}
</span>
{/if}
</div>
</div>
</CardSurface>
</div>
<style>
.stack-wrap {
position: relative;
width: 100%;
max-width: 18rem;
aspect-ratio: 5 / 7;
}
.layer {
position: absolute;
inset: 0;
background: hsl(var(--color-surface));
border: 1px solid hsl(var(--color-border));
border-radius: 0.875rem;
box-shadow: 0 1px 3px hsl(var(--color-foreground) / 0.06);
}
.cover-inner {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
padding: 1rem 1rem 1.125rem 1.375rem;
overflow: hidden;
}
.cover-corner {
position: absolute;
top: 0.875rem;
right: 0.875rem;
display: flex;
align-items: center;
gap: 0.375rem;
opacity: 0.85;
}
.featured-badge {
font-size: 0.75rem;
color: hsl(var(--color-primary));
font-weight: 700;
}
.cover-body {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 0.875rem;
padding: 2.5rem 0.5rem 0 0;
min-height: 0;
}
.cover-title {
margin: 0;
font-size: 1.0625rem;
font-weight: 600;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 3;
line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.cover-desc {
margin: 0;
font-size: 0.75rem;
color: hsl(var(--color-muted-foreground));
line-height: 1.4;
}
.cover-meta {
flex: 0 0 auto;
display: flex;
flex-wrap: wrap;
gap: 0.25rem 0.5rem;
font-size: 0.75rem;
color: hsl(var(--color-muted-foreground));
font-variant-numeric: tabular-nums;
}
.meta-stars {
display: inline-flex;
align-items: center;
gap: 0.2rem;
color: hsl(var(--color-primary));
font-weight: 500;
}
</style>

View file

@ -6,19 +6,43 @@
const { count = 6 }: Props = $props(); const { count = 6 }: Props = $props();
</script> </script>
<ul class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3" aria-busy="true" aria-label="Lade Decks"> <ul class="skeleton-row" aria-busy="true" aria-label="Lade Decks">
{#each Array.from({ length: count }) as _, i (i)} {#each Array.from({ length: count }) as _, i (i)}
<li <li class="skeleton-item animate-pulse">
class="animate-pulse rounded-lg border border-[hsl(var(--color-border))] bg-[hsl(var(--color-card))] p-4" <div class="skeleton-card"></div>
>
<div class="h-4 w-3/4 rounded bg-[hsl(var(--color-border))]"></div>
<div class="mt-2 h-3 w-full rounded bg-[hsl(var(--color-border))]/60"></div>
<div class="mt-1 h-3 w-5/6 rounded bg-[hsl(var(--color-border))]/60"></div>
<div class="mt-3 flex gap-2">
<div class="h-2 w-16 rounded bg-[hsl(var(--color-border))]/40"></div>
<div class="h-2 w-12 rounded bg-[hsl(var(--color-border))]/40"></div>
<div class="h-2 w-20 rounded bg-[hsl(var(--color-border))]/40"></div>
</div>
</li> </li>
{/each} {/each}
</ul> </ul>
<style>
.skeleton-row {
list-style: none;
margin: 0;
padding-block: 0 1rem;
display: flex;
flex-direction: row;
gap: 1rem;
overflow: hidden;
width: 100dvw;
margin-left: calc(50% - 50dvw);
}
.skeleton-row::before {
content: '';
flex-shrink: 0;
width: max(1rem, calc((100dvw - 72rem) / 2 + 1rem));
}
.skeleton-item {
flex: 0 0 auto;
width: 16rem;
}
.skeleton-card {
width: 100%;
aspect-ratio: 5 / 7;
border-radius: 0.875rem;
background: hsl(var(--color-border) / 0.5);
}
</style>

View file

@ -10,6 +10,7 @@
import EmptyState from '$lib/components/marketplace/EmptyState.svelte'; import EmptyState from '$lib/components/marketplace/EmptyState.svelte';
import SkeletonGrid from '$lib/components/marketplace/SkeletonGrid.svelte'; import SkeletonGrid from '$lib/components/marketplace/SkeletonGrid.svelte';
import { toasts } from '$lib/stores/toasts.svelte.ts'; import { toasts } from '$lib/stores/toasts.svelte.ts';
import { Fire, Star, MagnifyingGlass, Books } from '@mana/shared-icons';
let featured = $state<DeckListEntry[]>([]); let featured = $state<DeckListEntry[]>([]);
let trending = $state<DeckListEntry[]>([]); let trending = $state<DeckListEntry[]>([]);
@ -79,36 +80,32 @@
<title>Explore · Cardecky</title> <title>Explore · Cardecky</title>
</svelte:head> </svelte:head>
<div class="mx-auto max-w-6xl space-y-10"> <div class="space-y-10">
<header> <header>
<h1 class="text-3xl font-semibold">Cardecky-Library</h1> <h1 class="text-3xl font-semibold">Cardecky-Library</h1>
<p class="mt-2 text-sm text-[hsl(var(--color-muted-foreground))]">
Decks von der Verein-Community + KI-kuratierten Cardecky-Author. Subscribe für Live-Updates,
fork für eigenen Lern-Stand, ✏️ Verbesserungen via Pull-Request einreichen.
</p>
</header> </header>
{#if loadingExplore} {#if loadingExplore}
<section> <section>
<h2 class="mb-3 text-xl font-semibold">🔥 Trending</h2> <h2 class="section-head"><Fire size={20} weight="duotone" /> Trending</h2>
<SkeletonGrid count={6} /> <SkeletonGrid count={6} />
</section> </section>
{:else} {:else}
{#if featured.length > 0} {#if featured.length > 0}
<section> <section>
<h2 class="mb-3 text-xl font-semibold">★ Featured</h2> <h2 class="section-head"><Star size={20} weight="duotone" /> Featured</h2>
<DeckListGrid items={featured} /> <DeckListGrid items={featured} />
</section> </section>
{/if} {/if}
{#if trending.length > 0} {#if trending.length > 0}
<section> <section>
<h2 class="mb-3 text-xl font-semibold">🔥 Trending</h2> <h2 class="section-head"><Fire size={20} weight="duotone" /> Trending</h2>
<DeckListGrid items={trending} /> <DeckListGrid items={trending} />
</section> </section>
{:else if !loadingExplore && featured.length === 0} {:else if !loadingExplore && featured.length === 0}
<EmptyState <EmptyState
icon="📚" icon={Books}
title="Library ist noch leer" title="Library ist noch leer"
description="Bald gibt's hier viele Decks. Wenn du selbst publizieren willst: leg dir ein Author-Profil an." description="Bald gibt's hier viele Decks. Wenn du selbst publizieren willst: leg dir ein Author-Profil an."
ctaHref="/me/published" ctaHref="/me/published"
@ -118,7 +115,7 @@
{/if} {/if}
<section> <section>
<h2 class="mb-3 text-xl font-semibold">🔎 Stöbern</h2> <h2 class="section-head"><MagnifyingGlass size={20} weight="duotone" /> Stöbern</h2>
<form <form
class="mb-4 flex flex-wrap items-end gap-3" class="mb-4 flex flex-wrap items-end gap-3"
@ -182,3 +179,15 @@
{/if} {/if}
</section> </section>
</div> </div>
<style>
.section-head {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
font-size: 1.25rem;
font-weight: 600;
color: hsl(var(--color-foreground));
}
</style>

View file

@ -9,6 +9,7 @@
import { devUser } from '$lib/auth/dev-stub.svelte.ts'; import { devUser } from '$lib/auth/dev-stub.svelte.ts';
import EmptyState from '$lib/components/marketplace/EmptyState.svelte'; import EmptyState from '$lib/components/marketplace/EmptyState.svelte';
import { toasts } from '$lib/stores/toasts.svelte.ts'; import { toasts } from '$lib/stores/toasts.svelte.ts';
import { GitFork } from '@mana/shared-icons';
let forks = $state<Deck[]>([]); let forks = $state<Deck[]>([]);
let loading = $state(true); let loading = $state(true);
@ -72,7 +73,7 @@
<p class="text-sm text-[hsl(var(--color-muted-foreground))]">Lade…</p> <p class="text-sm text-[hsl(var(--color-muted-foreground))]">Lade…</p>
{:else if forks.length === 0} {:else if forks.length === 0}
<EmptyState <EmptyState
icon="🔱" icon={GitFork}
title="Noch nichts geforkt" title="Noch nichts geforkt"
description={'Forks geben dir eine eigene Lern-Kopie eines Marketplace-Decks. FSRS-Reviews bleiben bei dir; Updates des Original-Authors kannst du via „Update ziehen“ einspielen.'} description={'Forks geben dir eine eigene Lern-Kopie eines Marketplace-Decks. FSRS-Reviews bleiben bei dir; Updates des Original-Authors kannst du via „Update ziehen“ einspielen.'}
ctaHref="/explore" ctaHref="/explore"

View file

@ -7,6 +7,7 @@
import { devUser } from '$lib/auth/dev-stub.svelte.ts'; import { devUser } from '$lib/auth/dev-stub.svelte.ts';
import EmptyState from '$lib/components/marketplace/EmptyState.svelte'; import EmptyState from '$lib/components/marketplace/EmptyState.svelte';
import { toasts } from '$lib/stores/toasts.svelte.ts'; import { toasts } from '$lib/stores/toasts.svelte.ts';
import { ArrowCounterClockwise } from '@mana/shared-icons';
let items = $state<SubscriptionEntry[]>([]); let items = $state<SubscriptionEntry[]>([]);
let loading = $state(true); let loading = $state(true);
@ -44,7 +45,7 @@
<p class="text-sm text-[hsl(var(--color-muted-foreground))]">Lade…</p> <p class="text-sm text-[hsl(var(--color-muted-foreground))]">Lade…</p>
{:else if items.length === 0} {:else if items.length === 0}
<EmptyState <EmptyState
icon="↩︎" icon={ArrowCounterClockwise}
title="Noch keine Abos" title="Noch keine Abos"
description="Subscribe einen Deck im Explore, dann siehst du hier Updates des Authors." description="Subscribe einen Deck im Explore, dann siehst du hier Updates des Authors."
ctaHref="/explore" ctaHref="/explore"

View file

@ -0,0 +1,123 @@
Factfulness: Das 13-Fragen-Quiz und die Analyse unserer Weltsicht
Dieses Dokument enthält das berühmte 13-Fragen-Quiz aus dem Buch „Factfulness“ von Hans Rosling. Das Quiz wurde entwickelt, um unsere tief verwurzelten Vorurteile und veralteten Weltbilder zu testen. Roslings weltweite Umfragen zeigten, dass die meisten Menschen (selbst hochgebildete Experten) systematisch schlechter abschneiden als Schimpansen, die die Antworten blind erraten würden. Die Fragen belegen eindrucksvoll, dass sich die Welt in vielen Bereichen weitaus positiver entwickelt hat, als es unser „dramatischer Instinkt“ uns glauben lässt.
Die 13 Fragen zur Lage der Welt
Frage 1: Bildung von Mädchen
In allen einkommensschwachen Ländern auf der Welt: Wie viel Prozent der Mädchen beenden die Grundschule?
A: 20 Prozent
B: 40 Prozent
C: 60 Prozent
Richtige Antwort: C (60 Prozent)
Hintergrund: Unser Bild von „armen Ländern“ ist oft um Jahrzehnte veraltet. Die meisten Mädchen in den einkommensschwächsten Regionen der Welt haben heute Zugang zu grundlegender Schulbildung. Der Unterschied zwischen den Geschlechtern in der Grundschulbildung ist weltweit nahezu verschwunden.
Frage 2: Wo lebt die Weltbevölkerung?
Wo lebt die Mehrheit der Weltbevölkerung?
A: In Ländern mit niedrigem Einkommen
B: In Ländern mit mittlerem Einkommen
C: In Ländern mit hohem Einkommen
Richtige Antwort: B (In Ländern mit mittlerem Einkommen)
Hintergrund: Die Zweiteilung der Welt in „Entwicklungs- und Industrieländer“ existiert so nicht mehr. Etwa 75 % der Weltbevölkerung leben heute in Ländern mit mittlerem Einkommen. Dort gibt es funktionierende grundlegende Infrastrukturen, Gesundheitsversorgung und Strom.
Frage 3: Entwicklung der extremen Armut
In den letzten 20 Jahren hat sich der Anteil der in extremer Armut lebenden Weltbevölkerung...
A: ...fast verdoppelt.
B: ...ist in etwa gleich geblieben.
C: ...hat sich fast halbiert.
Richtige Antwort: C (fast halbiert)
Hintergrund: Dies ist einer der größten Triumphe der Menschheitsgeschichte, der jedoch kaum in den Nachrichten thematisiert wird. Millionen von Menschen sind in den letzten zwei Jahrzehnten aus der extremen Armut entkommen (viele davon in Asien).
Frage 4: Weltweite Lebenserwartung
Wie hoch ist die durchschnittliche Lebenserwartung in der Welt von heute?
A: 50 Jahre
B: 60 Jahre
C: 70 Jahre
Richtige Antwort: C (70 Jahre)
Hintergrund: Aktuell liegt die globale Lebenserwartung sogar bei ca. 72 Jahren. Die massive Senkung der Kindersterblichkeit durch Impfungen, sauberes Wasser und bessere Ernährung hat diesen globalen Durchschnitt stark angehoben.
Frage 5: Zukünftiges Bevölkerungswachstum (Kinder)
Es gibt heute etwa 2 Milliarden Kinder auf der Welt (Alter 0-15 Jahre). Wie viele Kinder wird es nach Schätzungen der UN im Jahr 2100 geben?
A: 4 Milliarden
B: 3 Milliarden
C: 2 Milliarden
Richtige Antwort: C (2 Milliarden)
Hintergrund: Wir haben „Peak Child“ (den Höhepunkt der Kinderzahl) bereits erreicht. Frauen weltweit bekommen im Durchschnitt nur noch ca. 2,4 Kinder. Die Anzahl der Kinder auf der Welt wächst nicht mehr weiter.
Frage 6: Gründe für das Bevölkerungswachstum
Die UN sagt voraus, dass die Weltbevölkerung bis 2100 um weitere 4 Milliarden wachsen wird. Was ist der Hauptgrund dafür?
A: Es wird mehr Kinder geben (unter 15 Jahren).
B: Es wird mehr Erwachsene geben (15 bis 74 Jahre).
C: Es wird mehr sehr alte Menschen geben (über 75 Jahre).
Richtige Antwort: B (Es wird mehr Erwachsene geben)
Hintergrund: Da die Zahl der Kinder nicht mehr steigt (siehe Frage 5), wächst die Bevölkerung durch den sogenannten „Fill-up-Effekt“. Die vielen Kinder, die in den vergangenen Jahrzehnten geboren wurden, wachsen heran und füllen die Altersgruppen der Erwachsenen auf.
Frage 7: Opfer von Naturkatastrophen
Wie hat sich die Zahl der jährlichen Todesfälle durch Naturkatastrophen in den letzten 100 Jahren entwickelt?
A: Sie hat sich mehr als verdoppelt.
B: Sie ist in etwa gleich geblieben.
C: Sie ist um mehr als die Hälfte gesunken.
Richtige Antwort: C (um mehr als die Hälfte gesunken)
Hintergrund: Trotz des Klimawandels sterben heute weit weniger Menschen an Naturkatastrophen (oft sogar bis zu 75% weniger). Der Grund: Bessere Frühwarnsysteme, stabile Gebäude und schnellere internationale Nothilfe.
Frage 8: Verteilung der Weltbevölkerung
Heute leben rund 7 Milliarden Menschen auf der Erde. Wie verteilen sie sich auf die Regionen (Amerika, Europa, Afrika, Asien)?
A: Amerika 1 Mrd. / Europa 1 Mrd. / Afrika 1 Mrd. / Asien 4 Mrd.
B: Amerika 1 Mrd. / Europa 1 Mrd. / Afrika 2 Mrd. / Asien 3 Mrd.
C: Amerika 2 Mrd. / Europa 1 Mrd. / Afrika 1 Mrd. / Asien 3 Mrd.
Richtige Antwort: A (1-1-1-4)
Hintergrund: Rosling nennt dies den „PIN-Code der Welt“: 1114. Der absolute Großteil der Menschheit (4 Milliarden) lebt in Asien. Bis zum Ende des Jahrhunderts wird sich Afrika voraussichtlich stark vergrößern, während der Westen (Amerika und Europa) bevölkerungstechnisch weiter schrumpft im globalen Verhältnis.
Frage 9: Globale Impfquoten
Wie viel Prozent der einjährigen Kinder auf der Welt sind gegen eine Krankheit geimpft?
A: 20 Prozent
B: 50 Prozent
C: 80 Prozent
Richtige Antwort: C (80 Prozent)
Hintergrund: 80 Prozent der Kinder weltweit erhalten elementare Basis-Impfungen (z.B. gegen Masern). Dies ist ein Beweis dafür, dass medizinische Basis-Logistik selbst in sehr abgelegene oder ärmere Regionen reicht.
Frage 10: Schulbildung von Frauen
Weltweit verbringen 30-jährige Männer durchschnittlich 10 Jahre in der Schule. Wie viele Jahre verbringen Frauen im gleichen Alter in der Schule?
A: 9 Jahre
B: 6 Jahre
C: 3 Jahre
Richtige Antwort: A (9 Jahre)
Hintergrund: Der historische Rückstand bei der Bildung von Mädchen und Frauen wird weltweit rasend schnell aufgeholt. Der absolute Gap in den Jahren auf der Schulbank ist heute gering.
Frage 11: Bedrohte Tierarten
Im Jahr 1996 wurden Tiger, Große Pandas und Spitzmaulnashörner als bedrohte Arten eingestuft. Wie viele dieser drei Arten sind heute noch stärker bedroht?
A: Zwei
B: Eine
C: Keine
Richtige Antwort: C (Keine)
Hintergrund: Naturschutzbemühungen, internationale Verbote und Schutzreservate funktionieren tatsächlich. Die Populationen aller drei genannten Arten haben sich stabilisiert oder vergrößert.
Frage 12: Zugang zu Strom
Wie viele Menschen auf der Welt haben (zumindest teilweise) Zugang zu Elektrizität?
A: 20 Prozent
B: 50 Prozent
C: 80 Prozent
Richtige Antwort: C (80 Prozent)
Hintergrund: Ein Leben gänzlich ohne Strom ist heutzutage eine globale Ausnahmeerscheinung geworden. Der größte Teil der Menschheit nutzt Handys, Licht und Kühlschränke.
Frage 13: Der Klimawandel
Globale Klimaexperten glauben, dass die Durchschnittstemperatur über die nächsten 100 Jahre...
A: ...wärmer wird.
B: ...gleich bleibt.
C: ...kälter wird.
Richtige Antwort: A (wärmer wird)
Hintergrund: Dies ist die einzige Frage im Quiz, bei der ein Großteil der Befragten besser abschnitt als der Schimpanse. Das zeigt, dass das Bewusstsein für die reale Gefahr der globalen Erwärmung weit verbreitet ist.
Warum irren wir uns so oft? Die 10 Instinkte
Hans Rosling beschreibt in Factfulness zehn menschliche Instinkte, die unsere Weltsicht verzerren und dazu führen, dass wir das Positive übersehen. Hier ist die vollständige Liste:
Instinkt
Erklärung & Auswirkung
1. Der Instinkt der Lücke
Wir neigen dazu, die Welt in "Wir" und "Die Anderen" oder "Arm" und "Reich" einzuteilen. Tatsächlich befindet sich der Großteil der Menschheit in der Mitte.
2. Der Instinkt der Negativität
Schlechte Nachrichten erreichen uns viel leichter und dominieren die Medien. Langsame, positive Entwicklungen sind hingegen keine Breaking News.
3. Der Instinkt der geraden Linie
Wir gehen davon aus, dass Trends (wie Bevölkerungswachstum) ewig in einer geraden Linie weitergehen. Oft verlaufen Trends jedoch als S-Kurven, flachen ab oder sinken.
4. Der Instinkt der Angst
Dinge, die furchteinflößend sind (Terror, Flugzeugabstürze, Haie), nehmen wir als viel wahrscheinlicher wahr, als sie statistisch tatsächlich sind.
5. Der Instinkt der Größe
Eine einzelne, isolierte Zahl wirkt oft extrem groß oder klein, bis man sie in einen Kontext setzt oder ins richtige Verhältnis (z.B. pro Kopf) rückt.
6. Der Instinkt der Verallgemeinerung
Wir stecken Menschen und Dinge vorschnell in Kategorien und übersehen dabei oft massive Unterschiede innerhalb einer Gruppe und wichtige Gemeinsamkeiten zwischen verschiedenen Gruppen.
7. Der Instinkt des Schicksals
Wir nehmen fälschlicherweise an, dass angeborene Eigenschaften die Bestimmung von Menschen, Ländern oder Kulturen unveränderlich vorherbestimmen. Tatsächlich findet stetiger Wandel statt.
8. Der Instinkt der einzigen Perspektive
Wir bevorzugen oft einfache Ideen und Werkzeuge für alle Probleme, was unsere Sicht verengt. Komplexe Probleme erfordern meist die Betrachtung aus verschiedenen Blickwinkeln.
9. Der Instinkt der Schuldzuweisung
Wenn etwas schiefgeht, suchen wir reflexartig nach einem klaren, einfachen Schuldigen. Dabei ignorieren wir meist die komplexeren, systemischen Ursachen.
10. Der Instinkt der Dringlichkeit
Das Gefühl von "Jetzt oder nie" verleitet uns zu unüberlegten Handlungen und blockiert klares, analytisches Denken. In den meisten Fällen ist die Lage weniger dringend, als sie scheint, und erlaubt ein genaueres Abwägen.
Fazit: Factfulness ist kein naiver Optimismus, sondern die Aufforderung, sich auf Daten und Fakten zu stützen, um eine fundierte und lösungsorientierte Sicht auf unsere globale Gesellschaft zu entwickeln.