/* ============================================================================
   Spielekiste — Design-System
   Eine Datei, ein Theme. Hub UND Rechtsseiten laden genau dieses Stylesheet;
   das GameKit-HUD hängt sich später an dieselben Tokens.

   GESTALTUNGSRICHTUNG: "Spielekatalog" — kräftige Groteske, EIN Signalrot für
   alles Bedienbare, Kategorien als farbcodierte Kapitel. Kein Neon, kein
   Verlauf, keine Glasoptik, keine Emoji: Energie kommt aus Typografie, Farbfläche
   und den Kachelbildern, nicht aus Effekten.

   Die Fassung davor war bewusst Zeitungspapier (gedeckt, entsättigt). Das ist
   überholt: Seit die Kacheln echte Screenshots tragen, ist der Rahmen drumherum
   heller, kühler und gesättigter — ein grauer Rahmen macht bunte Bilder nicht
   besser. Der Katalog läuft außerdem über die VOLLE Fensterbreite (siehe --rand);
   nur Fließtext behält seine Lesespalte.

   ZIELGRUPPE: 16+ UND Rentner/Brettspieler gleichzeitig. Daraus folgt hart:
   Fließtext min. 17px, Kontraste durchgerechnet nach WCAG AA (Zahlen unten,
   erzeugt von scripts/kontrast.mjs), Klickflächen min. 44px, Wortlabels statt
   Icon-Rätsel. "Bunter" darf nie gegen diese Punkte gehen.

   ----------------------------------------------------------------------------
   SCHRIFTEN (beide SIL Open Font License 1.1, selbst gehostet, kein CDN):
     Bricolage Grotesque — Copyright 2022 The Bricolage Grotesque Project Authors
       https://github.com/ateliertriay/bricolage
     Instrument Sans — Copyright 2022 The Instrument Sans Project Authors
       https://github.com/Instrument/instrument-sans
   Lizenztexte liegen vollständig neben den Dateien in /vendor-fonts/.
   Kein Google-Fonts-CDN: DSGVO-Risiko und ein Fremdserver im kritischen Pfad.
   ============================================================================ */

/* ---------------------------------------------------------------- Schriften */
/* Nur die wght-Achse, nur latin + latin-ext. Die opsz/wdth-Schnitte und die
   vietnamesischen Subsets bleiben weg: unbenutzt = nicht ausliefern.
   Deutsch liegt komplett in `latin` (ä ö ü ß) — latin-ext lädt dank
   unicode-range in der Praxis nie mit. */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;          /* Variable Font: eine Datei, ganze Achse */
  font-display: swap;
  src: url(../vendor-fonts/bricolage-grotesque-latin-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url(../vendor-fonts/bricolage-grotesque-latin-ext-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../vendor-fonts/instrument-sans-latin-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../vendor-fonts/instrument-sans-latin-ext-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------------- Tokens */
:root {
  color-scheme: light dark;

  /* --- Farbe: Grundpalette --------------------------------------------------
     Hell ist der Normalfall. Begründung: Die Seite muss für Rentner genauso
     lesbar sein wie für 16-Jährige, und heller Grund ist bei Alterssichtigkeit
     die verlässlichere Wahl. Dunkel kommt über prefers-color-scheme.

     Die Palette war ursprünglich Zeitungspapier: gedeckt, entsättigt, ein
     einziges Rot. Als Spielekatalog war das zu brav — die Kacheln tragen jetzt
     bunte Screenshots, und ein grauer Rahmen drumherum macht sie nicht besser.
     Also: heller, kühler, gesättigter. Was NICHT verhandelbar ist und deshalb
     nachgerechnet wird (scripts/kontrast.mjs, Zahlen im Block "Kontraste"):
     Fließtext 4,5:1, Bedienrahmen 3:1. "Bunter" darf nie "blasser" heißen —
     entsättigter Text auf hellem Grund ist genau das, was ältere Augen als
     Erstes verlieren. */
  --bg:           #F2F4F9;  /* Seitengrund — leicht kühl statt Papierbeige */
  --surface:      #FFFFFF;  /* Karten, Eingabefelder */
  --surface-sunk: #E4E8F2;  /* eingelassene Flächen, Hover */
  --ink:          #15161D;  /* Haupttext */
  --ink-mid:      #4E5464;  /* Sekundärtext, Meta — dunkler als vorher: der Kachel-
                               text war das, was als "zu blass" aufgefallen ist */
  --line:         #D5DAE6;  /* Deko-Haarstrich, trennt nur optisch */
  --line-strong:  #7C8496;  /* Rahmen von Bedienelementen — muss 3:1 halten */
  --accent:       #D62410;  /* Signalrot: ALLES Bedienbare, sonst nichts */
  --accent-hover: #AC1B0A;
  --accent-ink:   #FFFFFF;  /* Text auf Signalrot */
  --accent-wash:  #FDE8E4;  /* Signalrot als Fläche, sehr zurückgenommen */

  /* --- Typografie -----------------------------------------------------------
     Zwei Familien, mehr nicht: Bricolage für Überschriften (hat Charakter),
     Instrument Sans für Text (ruhig, gut lesbar). Beide OFL, beide selbst gehostet.
     Die Skala ist in rem: so folgt sie der Browser-Schriftgröße des Nutzers —
     entscheidend, wenn jemand seine Schrift dauerhaft größer gestellt hat. */
  --font-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --font-text:    'Instrument Sans', system-ui, sans-serif;

  --t-meta:  0.8125rem; /* 13px — NUR Meta/Zähler, nie Fließtext */
  --t-small: 0.9375rem; /* 15px — Hilfstext, Tag-Labels */
  --t-body:  1.0625rem; /* 17px — Basis. Untergrenze, nicht Zielwert. */
  --t-lead:  1.1875rem; /* 19px — Einleitung, FAQ-Fragen */
  --t-h3:    1.3125rem; /* 21px */
  --t-h2:    1.875rem;  /* 30px */
  --t-h1:    clamp(2.5rem, 5.5vw, 4rem); /* 40–64px */

  --lh-tight: 1.05;  /* Displayzeilen */
  --lh-snug:  1.3;   /* Überschriften, Kartentitel */
  --lh-text:  1.65;  /* Fließtext — bewusst großzügig */

  /* --- Abstände: 4px-Raster ------------------------------------------------- */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px;

  /* --- Radien: dokumentierte 3-Stufen-Regel ---------------------------------
     Genau drei Werte, jeder mit einer Zuständigkeit. Nicht mischen.
       flat    = Bildflächen und Piktogramm-Panels (randscharf, wie gedruckt)
       control = alles Bedienbare: Button, Eingabe, Chip, Tag
       panel   = Container: Karte, Kasten, Details
     Keine Pillen (999px). Genau die machten vorher alles gleich weich. */
  --r-flat:    0;
  --r-control: 6px;
  --r-panel:   10px;

  /* --- Schatten -------------------------------------------------------------
     Sparsam und in den Papierton getönt, nie reines Schwarz. Nur beim Hover:
     im Ruhezustand trägt der Haarstrich die Abgrenzung. */
  --shadow-lift: 0 6px 20px rgba(23, 24, 28, .13);

  /* --- Maße ----------------------------------------------------------------
     Der Katalog läuft über die VOLLE Fensterbreite — es gibt bewusst kein
     `--wrap` mehr. Ein 1240px-Korridor ließ auf einem breiten Monitor links und
     rechts je eine Handbreit leer und presste die Kacheln in die Mitte; bei
     einem Katalog ist die Fläche aber der Inhalt. Statt einer Maximalbreite nur
     ein mitwachsender Seitenrand.
     `--wrap-text` bleibt: 68 Zeichen ist die Lesegrenze für FLIESSTEXT (AGB,
     Datenschutz, der SEO-Text unten). Eine Textzeile über 2560px wäre unlesbar —
     das ist kein Widerspruch zur Vollbreite, sondern der Grund für zwei Tokens. */
  --rand:      clamp(16px, 2.2vw, 40px); /* Seitenrand, wächst mit dem Fenster */
  --wrap-text: 68ch;   /* Lesespalte: Fließtext und Rechtsseiten */
  --tap:       44px;   /* Mindest-Klickfläche. Untergrenze, nicht Zielwert. */

  /* --- Bewegung -------------------------------------------------------------
     Bewusst niedrig gehalten: keine Scroll-Effekte, keine Endlosschleifen.
     Bewegung nur als Quittung auf eine Eingabe (Hover, Klick, Fokus). */
  --ease: cubic-bezier(.2, .7, .3, 1);
  --fast: .14s;

  /* --- Ebenen: eine Skala, keine z-index-Willkür ---------------------------- */
  --z-header: 50;
  --z-hud:    60;  /* reserviert fürs GameKit-HUD oben rechts */
  --z-skip:   100;
}

/* --- Dunkelmodus: dieselben Token-Namen, andere Werte ---------------------- */
@media (prefers-color-scheme: dark) {
  :root {
    /* Nicht Neutralgrau, sondern ein tiefes Blau: Es lässt bunte Kacheln leuchten,
       statt sie wie Grau nur abzudunkeln. Der Sekundärtext ist deutlich heller als
       vorher (#A2A6B0 -> #BFC5D6) — er war das, was im Dunkelmodus wegsackte. */
    --bg:           #12141F;
    --surface:      #1C1F2E;
    --surface-sunk: #272B3D;
    --ink:          #F5F7FC;
    --ink-mid:      #BFC5D6;
    --line:         #333850;
    --line-strong:  #7B839B;
    --accent:       #FF8F5E;
    --accent-hover: #FFB08A;
    --accent-ink:   #1A0C06;
    --accent-wash:  #3A2018;
    --shadow-lift:  0 6px 20px rgba(0, 0, 0, .5);
  }
}

/* ============================================================================
   KATEGORIEN — farbcodierte Kapitel des Katalogs
   Pro Kategorie nur ZWEI benutzte Tokens:
     --cat-panel = Fläche der Kachel        --cat-mark = Piktogramm + Tag-Text
   Die Familie ist absichtlich gedämpft. Nur das Signalrot ist gesättigt, damit
   "anklickbar" immer eindeutig bleibt und die Kacheln nicht wie Buttons wirken.
   Alle zehn Paare liegen eng beieinander (5,2:1 bis 7,2:1) — das ist der Grund,
   warum sie wie eine Familie wirken und nicht wie zehn zufällige Farben.
   ============================================================================ */
.cat-action      { --cat-panel: #FFDFD1; --cat-mark: #C22E00; }
.cat-rennen      { --cat-panel: #D8E6FF; --cat-mark: #0B4FD1; }
.cat-geschick    { --cat-panel: #CBF0EC; --cat-mark: #00706B; }
.cat-multiplayer { --cat-panel: #D3F2D5; --cat-mark: #1A7A2E; }
.cat-strategie   { --cat-panel: #E3DEFF; --cat-mark: #4B32C9; }
.cat-sport       { --cat-panel: #E8F3C9; --cat-mark: #4F6B00; }
.cat-sandbox     { --cat-panel: #FFE9C4; --cat-mark: #92560A; }
.cat-denken      { --cat-panel: #D5EBFA; --cat-mark: #10557E; }
.cat-lifestyle   { --cat-panel: #FFDCF0; --cat-mark: #B01277; }
.cat-verbinden   { --cat-panel: #FFDDE4; --cat-mark: #C01340; }

@media (prefers-color-scheme: dark) {
  /* Gedreht: die helle Tönung wird zur Marke, ein tiefer Ton zur Fläche. */
  .cat-action      { --cat-panel: #4A1B08; --cat-mark: #FFB596; }
  .cat-rennen      { --cat-panel: #12294F; --cat-mark: #9CC2FF; }
  .cat-geschick    { --cat-panel: #073633; --cat-mark: #6FE0D6; }
  .cat-multiplayer { --cat-panel: #10381A; --cat-mark: #7FE092; }
  .cat-strategie   { --cat-panel: #241C55; --cat-mark: #B7A6FF; }
  .cat-sport       { --cat-panel: #2C3607; --cat-mark: #C4E05A; }
  .cat-sandbox     { --cat-panel: #422A05; --cat-mark: #FFC066; }
  .cat-denken      { --cat-panel: #0F2C3E; --cat-mark: #86CDF2; }
  .cat-lifestyle   { --cat-panel: #451334; --cat-mark: #FF9ED8; }
  .cat-verbinden   { --cat-panel: #4C1424; --cat-mark: #FF9AAC; }
}

/* ============================================================================
   KONTRASTE — nachgerechnet, nicht geschätzt (WCAG 2.1, sRGB-Relativluminanz)
   Fließtext/AA verlangt 4,5:1, Bedienelement-Ränder/AA 3:1.

   DIESE ZAHLEN NICHT VON HAND PFLEGEN: `node scripts/kontrast.mjs` liest die
   Werte aus dieser Datei und rechnet sie nach. Nach JEDER Farbänderung laufen
   lassen und den Block hier ersetzen — eine Kontrastangabe, die niemand
   nachrechnet, ist beim nächsten Farbdreher still falsch. Das Skript bricht mit
   Exit-Code 1 ab, wenn eine Schwelle reißt.

   Stand: Palette "heller, kühler, gesättigter" (gemessen, nicht geschätzt)

   HELL                                      DUNKEL
     Haupttext auf Papier      16,39:1         Haupttext auf Papier      17,10:1
     Haupttext auf Karte       18,04:1         Haupttext auf Karte       15,25:1
     Sekundärtext auf Papier    6,87:1         Sekundärtext auf Papier   10,63:1
     Sekundärtext auf Karte     7,56:1         Sekundärtext auf Karte     9,47:1
     Akzent-Link auf Papier     4,63:1         Akzent-Link auf Papier     8,16:1
     Akzent-Link auf Karte      5,10:1         Akzent-Link auf Karte      7,27:1
     Buttontext auf Akzent      5,10:1         Buttontext auf Akzent      8,50:1
     Bedienrahmen auf Karte     3,75:1         Bedienrahmen auf Karte     4,33:1
     Bedienrahmen auf Papier    3,41:1         Bedienrahmen auf Papier    4,86:1

   Kategorie-Piktogramm auf der eigenen Kachelfläche (je 10 Paare):
     hell   4,51:1 (Multiplayer) bis 6,52:1 (Denken)
     dunkel 7,22:1 (Strategie)   bis 8,64:1 (Sport)

   Jedes Paar besteht AA. Der Sekundärtext ist mit der bunteren Palette BESSER
   geworden (6,00 -> 6,87 hell, 7,48 -> 10,63 dunkel): "bunter" hieß hier
   ausdrücklich nicht "blasser". --line ist bewusst schwach: reine Deko, kein
   Bedienelement-Rand, deshalb steht es nicht in der Prüfliste.
   ============================================================================ */

/* ------------------------------------------------------------------- Basis */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: var(--lh-text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--lh-snug);
  letter-spacing: -.02em;
  font-weight: 700;
  text-wrap: balance;   /* verhindert Schusterjungen in Überschriften */
}

a { color: var(--accent); }
a:hover { color: var(--accent-hover); }

/* Ein Fokusstil für die ganze Seite. Dick genug, um ihn auch aus 60 cm
   Abstand auf einem Laptop zu sehen. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-control);
}

::selection { background: var(--accent); color: var(--accent-ink); }

img, svg { display: block; max-width: 100%; }

.wrap { width: 100%; padding-inline: var(--rand); }
/* Ausnahme und einzige: Fließtext bekommt seine Lesespalte zurück. Ohne das liefe
   der Datenschutztext auf einem 32-Zoll-Monitor als 300-Zeichen-Zeile durchs Bild. */
.wrap-text, .prose { max-width: var(--wrap-text); }

/* Nur für Screenreader. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: var(--s-3); top: -100px; z-index: var(--z-skip);
  background: var(--accent); color: var(--accent-ink);
  font-weight: 700; text-decoration: none;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-control);
}
.skip:focus { top: var(--s-3); color: var(--accent-ink); }

/* ---------------------------------------------------------------- Kopfzeile */
.site {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--bg);            /* deckend, kein Blur: Text bleibt lesbar */
  border-bottom: 1px solid var(--line);
}
.site-in {
  display: flex; align-items: center; gap: var(--s-5);
  min-height: 64px;                  /* Kopfzeile bleibt unter 80px */
  padding-inline: var(--rand);       /* fluchtet mit dem Katalog darunter */
  /* Rechts bleibt Platz frei: dort hängt das GameKit-HUD (Coins + Konto). */
  padding-right: clamp(var(--s-5), 3vw + 130px, 230px);
}
.brand {
  display: inline-flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-display); font-weight: 800; font-size: 1.25rem;
  letter-spacing: -.03em; color: var(--ink); text-decoration: none;
}
.brand:hover { color: var(--ink); }
.brand-mark { width: 26px; height: 26px; flex: none; }
/* Farbe per CSS-Regel, NICHT per fill="var(…)"-Attribut: var() in
   Präsentationsattributen wird von Browsern nicht ersetzt, die Marke wäre schwarz. */
.brand-mark .bm-bg { fill: var(--accent); }
.brand-mark .bm-fg { fill: var(--accent-ink); }
.site-nav { display: flex; gap: var(--s-1); margin-left: auto; }
.site-nav a {
  display: inline-flex; align-items: center; min-height: var(--tap);
  padding-inline: var(--s-3); border-radius: var(--r-control);
  color: var(--ink-mid); text-decoration: none; font-size: var(--t-small); font-weight: 600;
}
.site-nav a:hover { color: var(--ink); background: var(--surface-sunk); }
@media (max-width: 800px) { .site-nav { display: none; } }

/* ------------------------------------------------------------------ Buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap);
  padding: var(--s-3) var(--s-5);
  border: 1px solid transparent; border-radius: var(--r-control);
  font-family: var(--font-text); font-size: var(--t-body); font-weight: 700;
  line-height: 1.2; white-space: nowrap;   /* Buttontext bricht nie um */
  text-decoration: none; cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-hover); color: var(--accent-ink); }
.btn-secondary {
  background: var(--surface); color: var(--ink); border-color: var(--line-strong);
}
.btn-secondary:hover { background: var(--surface-sunk); color: var(--ink); }
/* Taktile Quittung: der Button gibt beim Drücken nach. */
.btn:active { transform: translateY(1px); }

/* ---------------------------------------------------------- Abschnittsköpfe */
section { scroll-margin-top: 80px; }
h2 { font-size: var(--t-h2); }
.sec-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s-3); margin-bottom: var(--s-5);
}
.sec-note { color: var(--ink-mid); font-size: var(--t-small); }

/* ============================================================================
   SPIELKACHEL — bildzuerst

   Das Vorschaubild IST die Kachel (/covers/<id>.jpg, 640x360, erzeugt von
   scripts/make-covers.mjs). Darunter nur Name und Kategorie als Beschriftung.
   Kein Rahmen, keine Karte, kein Kasten: 21 gerahmte Kästen nebeneinander sind
   ein Formular, kein Katalog. Was die Kachel trägt, ist das Bild.

   Das Piktogramm-System (Kategoriefläche + Zeichen + gewürfelte Textur) liegt
   DAHINTER und trägt die Kachel, solange kein Bild da ist: neues Spiel, Bild
   kaputt, Bildanzeige aus, Ladephase. Deshalb ist es nicht entfernt, sondern
   zum Unterbau geworden. Regeln stehen im Hub am Piktogramm-Baukasten.
   ============================================================================ */
.raster {
  display: grid; gap: var(--s-4);
  /* Dicht: der Betreiber will alle Spiele auf einen Blick, ohne Scrollen.
     178px ergibt auf 1440px sechs Spalten -> 21 Spiele in vier Reihen. */
  grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
}
@media (max-width: 480px) {
  .raster { grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: var(--s-3); }
}

.card { position: relative; }
/* [hidden] muss den display-Wert schlagen: Der Filter blendet über das Attribut
   aus, und Autoren-CSS gewinnt sonst gegen die Browser-Voreinstellung. Genau
   dieser Fehler hat im GameKit schon einmal ein "verstecktes" Overlay sichtbar
   gelassen. */
.card[hidden] { display: none; }

.card-link {
  display: block; color: var(--ink); text-decoration: none;
  border-radius: var(--r-panel);
}
.card-link:hover { color: var(--ink); }

.card-art {
  display: block; position: relative;
  /* Fest verdrahtet, damit der Platz steht, BEVOR das Bild da ist. Ohne das
     springt beim Nachladen von 21 Bildern das ganze Raster. */
  aspect-ratio: 16 / 9;
  background: var(--cat-panel);
  border-radius: var(--r-panel);
  overflow: hidden;
  transition: box-shadow var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.card-art > svg, .card-img { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Textur und Piktogramm holen ihre Farbe aus der Kategorie — deshalb steht in
   der SVG-Ausgabe keine einzige Farbe, nur diese zwei Klassen. */
.art-texture { stroke: var(--cat-mark); opacity: .14; }
.art-glyph   { stroke: var(--cat-mark); }

.card-img {
  object-fit: cover; display: block;
  transition: transform .3s var(--ease);
}
/* Kein Cover oder Bild kaputt: Piktogramm übernimmt. */
.card.kein-bild .card-img { display: none; }

.card:hover .card-art, .card:focus-within .card-art {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lift);
}
.card:hover .card-img { transform: scale(1.05); }
@media (prefers-reduced-motion: reduce) {
  .card-img, .card-art { transition: none; }
  .card:hover .card-img, .card:hover .card-art { transform: none; }
}

.card-body { padding: var(--s-3) 2px 0; }
.card-title {
  /* Fließtextschrift, nicht Display: In dieser Größe wäre die Groteske eng und
     schlecht lesbar, und die Zielgruppe umfasst ausdrücklich ältere Menschen. */
  font-family: var(--font-text);
  font-size: var(--t-small); font-weight: 700;
  line-height: 1.25; letter-spacing: -.01em;
  /* Zweizeilig deckeln: lange Namen sollen die Kachelhöhe nicht auseinandertreiben. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card:hover .card-title { text-decoration: underline; text-underline-offset: 2px; }
/* Wortlabel, kein Rätsel: die Kategorie steht ausgeschrieben da. Bewusst in
   --ink-mid (6,00:1 auf Papier, nachgerechnet oben) statt in der Kategoriefarbe:
   die ist auf --cat-panel vermessen, nicht auf dem Seitengrund, und 21 farbige
   Labels neben 21 Bildern sind Konfetti. Die Farbe trägt das Register links. */
.card-tag {
  display: block; margin-top: 1px;
  color: var(--ink-mid); font-size: var(--t-meta); font-weight: 500;
}

/* ------------------------------------------------------------- Favoritenstern
   Liegt NEBEN dem <a>, nicht darin: Ein Button in einem Link ist ungültiges HTML
   und macht die Tastaturbedienung unbrauchbar. Deshalb absolut über der Kachel. */
.fav {
  position: absolute; top: 6px; right: 6px; z-index: 1;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: color-mix(in srgb, var(--bg) 74%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink); line-height: 0;
  opacity: 0;
  transition: opacity var(--fast) var(--ease), color var(--fast) var(--ease),
              background var(--fast) var(--ease);
}
.fav svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
/* Auf Zeigergeräten erst beim Annähern zeigen — das Raster soll ruhig bleiben.
   Auf Touch gibt es kein Hover, dort MUSS er immer sichtbar sein, sonst ist die
   Funktion auf dem Handy schlicht unerreichbar. */
.card:hover .fav, .fav:focus-visible { opacity: 1; }
@media (hover: none) { .fav { opacity: 1; } }
.fav:hover { color: var(--accent); background: var(--bg); }
/* Gesetzter Favorit bleibt immer sichtbar — sonst weiß niemand, was gemerkt ist. */
.fav[aria-pressed="true"] { opacity: 1; color: var(--accent); }
.fav[aria-pressed="true"] svg { fill: var(--accent); }

/* ------------------------------------------------------------------- Suche
   Die Kategorien sind KEINE Chips mehr, sondern das Register in der Schiene
   links (.cat im Hub). Die alten .toolbar/.chip-Regeln standen hier ohne
   Benutzer und sind deshalb raus — totes CSS in einem Design-System ist eine
   Falle: der Nächste hält es für die gültige Lösung. */
.search { position: relative; }
.search label { display: block; font-size: var(--t-small); font-weight: 600; margin-bottom: var(--s-2); }
.search input {
  width: 100%; min-height: var(--tap);
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-text); font-size: var(--t-body);
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--r-control);
}
.search input::placeholder { color: var(--ink-mid); }  /* 6,91:1 — auch Platzhalter lesbar */
.search input:focus-visible { border-color: var(--accent); }

.count { color: var(--ink-mid); font-size: var(--t-small); font-variant-numeric: tabular-nums; }

/* Leerzustand: sagt, was zu tun ist, statt nur "nichts gefunden". */
.empty {
  border: 1px dashed var(--line-strong); border-radius: var(--r-panel);
  padding: var(--s-8) var(--s-5); text-align: center;
}
.empty h3 { font-size: var(--t-h3); margin-bottom: var(--s-2); }
.empty p { color: var(--ink-mid); margin-bottom: var(--s-5); }

/* ---------------------------------------------------------------- Fließtext */
.prose { max-width: var(--wrap-text); }
.prose h2 { margin-bottom: var(--s-4); }
.prose h3 { font-size: var(--t-h3); margin: var(--s-6) 0 var(--s-3); }
.prose h4 { font-size: var(--t-lead); margin: var(--s-5) 0 var(--s-2); }
.prose p { margin-bottom: var(--s-4); }
.prose ul, .prose ol { margin: 0 0 var(--s-4) var(--s-5); }
.prose li { margin-bottom: var(--s-2); }
.prose strong { font-weight: 700; }

/* FAQ und Rechtsseiten teilen sich diesen Aufklapper. */
details {
  border-bottom: 1px solid var(--line);
  padding: var(--s-4) 0;
}
details summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  min-height: calc(var(--tap) - var(--s-4));
  font-family: var(--font-display); font-size: var(--t-lead); font-weight: 700;
  cursor: pointer; list-style: none;
}
details summary::-webkit-details-marker { display: none; }
/* Plus/Minus statt Dreieck: das versteht auch, wer noch nie ein Accordion gesehen hat. */
details summary::after {
  content: "+"; flex: none;
  font-family: var(--font-display); font-size: 1.5rem; font-weight: 400; line-height: 1;
  color: var(--accent);
}
details[open] summary::after { content: "\2212"; }
details summary:hover { color: var(--accent); }
details > *:not(summary) { margin-top: var(--s-3); color: var(--ink-mid); }

/* ---------------------------------------------------------------- Fußzeile */
footer {
  border-top: 1px solid var(--line);
  margin-top: var(--s-9);
  padding: var(--s-7) 0 var(--s-8);
}
.foot-in {
  display: flex; flex-wrap: wrap; gap: var(--s-5) var(--s-8);
  justify-content: space-between; align-items: flex-start;
}
.foot-note { color: var(--ink-mid); font-size: var(--t-small); max-width: 44ch; margin-top: var(--s-3); }
.foot-links { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-5); }
.foot-links a {
  display: inline-flex; align-items: center; min-height: var(--tap);
  color: var(--ink-mid); text-decoration: none; font-weight: 600;
}
.foot-links a:hover { color: var(--accent); text-decoration: underline; }

/* Kategorie-Links über der Fußzeile (Hub). Ruhig, textig, crawlbar — führen in die
   redaktionellen Kategorie-/Spieleseiten. */
.foot-entdecken { padding-bottom: var(--s-6); margin-bottom: var(--s-6); border-bottom: 1px solid var(--line); }
.foot-entdecken h2 { font-size: var(--t-h3); margin-bottom: var(--s-4); }
.foot-entdecken ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-5);
}
.foot-entdecken a {
  display: inline-flex; align-items: center; min-height: 40px;
  color: var(--ink-mid); text-decoration: none; font-weight: 600; font-size: var(--t-small);
}
.foot-entdecken a:hover { color: var(--accent); text-decoration: underline; }
.foot-entdecken strong { color: var(--ink); }

/* ------------------------------------------------------------ Rechtsseiten */
/* Vier Seiten Pflichttext. Sie sollen ruhig und lesbar sein, sonst nichts.
   Sie benutzen dieselben Tokens wie der Hub — das ist der ganze Punkt an
   "ein Theme für alles": keine zweite Palette, keine zweite Schrift. */
.legal {
  max-width: var(--wrap-text); margin-inline: auto;
  padding: var(--s-7) var(--s-5) var(--s-8);
}
.legal h1 { font-size: clamp(2rem, 4vw, 2.75rem); }
.legal h2 { margin: var(--s-7) 0 var(--s-3); }
.legal .sub { color: var(--ink-mid); font-size: var(--t-lead); margin-top: var(--s-3); }
.back {
  display: inline-flex; align-items: center; min-height: var(--tap);
  margin-left: auto; font-weight: 600; font-size: var(--t-small);
  text-decoration: none; white-space: nowrap;
}
.back:hover { text-decoration: underline; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--s-7) 0; }

/* Warnkasten oben auf jeder Rechtsseite. Trägt als einziges Element der
   Rechtsseiten das Signalrot — dann heißt Rot hier auch wirklich "Achtung". */
.notice {
  display: flex; gap: var(--s-4); align-items: flex-start;
  background: var(--accent-wash); border: 1px solid var(--accent);
  border-radius: var(--r-panel); padding: var(--s-4); margin: var(--s-5) 0;
}
/* Wortlabel statt Warnsymbol: "Achtung" versteht jeder, ein Piktogramm nicht. */
.notice .ic {
  flex: none; background: var(--accent); color: var(--accent-ink);
  border-radius: var(--r-control); padding: 2px var(--s-2);
  font-size: var(--t-meta); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
}
.notice b { display: block; margin-bottom: var(--s-1); }
.notice p { color: var(--ink); font-size: var(--t-small); margin: 0; }

/* Vom Betreiber auszufüllen. Bewusst NICHT rot: das sind offene Aufgaben,
   keine Warnungen. Gestreifter Rand plus Label, damit sie beim Überfliegen
   auffallen und niemand sie versehentlich live gehen lässt. */
.fill {
  display: block; margin: var(--s-3) 0 var(--s-4);
  background: var(--surface-sunk); border: 1px dashed var(--line-strong);
  border-radius: var(--r-control); padding: var(--s-3) var(--s-4);
  font-size: var(--t-small); color: var(--ink);
}
.fill::before {
  content: "Auszufüllen"; display: block; margin-bottom: var(--s-1);
  font-size: var(--t-meta); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-mid);
}

/* Inhaltsverzeichnis und Schlussbemerkung: gleicher Kasten, gleiche Regeln. */
.toc, .todo-count {
  border: 1px solid var(--line); border-radius: var(--r-panel);
  background: var(--surface); padding: var(--s-4) var(--s-5);
}
.toc { margin: var(--s-5) 0; }
.todo-count { margin-top: var(--s-6); color: var(--ink-mid); font-size: var(--t-small); }
.toc b { font-size: var(--t-small); }
.toc ol { margin: var(--s-3) 0 0 var(--s-5); }
.toc li { margin-bottom: var(--s-1); }
.toc a { display: inline-flex; align-items: center; min-height: 32px; text-decoration: none; }
.toc a:hover { text-decoration: underline; }

/* Datenschutz: Verarbeitungstabellen. Schmale Viewports scrollen die Tabelle,
   nicht die Seite — sonst wackelt das ganze Layout horizontal. */
.tablewrap {
  overflow-x: auto; margin-bottom: var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-panel);
}
table { border-collapse: collapse; width: 100%; min-width: 560px; font-size: var(--t-small); }
th, td { text-align: left; padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--line); vertical-align: top; }
th { background: var(--surface-sunk); font-weight: 700; }
tr:last-child td { border-bottom: 0; }
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9em; background: var(--surface-sunk);
  border-radius: 4px; padding: 1px 5px;
}

/* Widerruf: Merkkasten und Musterformular. */
.key {
  border: 1px solid var(--line-strong); border-left: 4px solid var(--ink);
  border-radius: var(--r-panel); background: var(--surface);
  padding: var(--s-4) var(--s-5); margin: var(--s-5) 0;
}
.key b { display: block; margin-bottom: var(--s-2); }
.key p { color: var(--ink); margin: 0; }
.key p + p { margin-top: var(--s-3); }
.form {
  border: 1px solid var(--line); border-radius: var(--r-panel);
  background: var(--surface); padding: var(--s-5); margin: var(--s-5) 0;
}
.form h3 { margin-top: 0; }
.form ul { list-style: none; margin-left: 0; }
.form li { margin-bottom: var(--s-3); }
.form .line { display: inline-block; min-width: 220px; border-bottom: 1px dashed var(--line-strong); }
.form .hint { color: var(--ink-mid); font-size: var(--t-meta); }

/* ------------------------------------------------------------- Bewegung aus */
/* Wer Bewegung abbestellt hat, bekommt keine. Gilt für alles, ohne Ausnahme. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
