/* ============================================================================
 * DASHBOARD (NEU) — Sektionen und System-Teaser
 * ----------------------------------------------------------------------------
 * Ergaenzt dashboard.css, ersetzt es nicht: Die uebernommenen Bloecke (Termine,
 * Fortschritt, Ranglisten) bringen ihr Aussehen mit. Hier steht nur, was neu
 * dazukommt — der Sektionsrahmen und die Teaser-Kacheln.
 *
 * Joy of Use ist hier kein Beiwerk, sondern Auftrag (Tim, 11.08.2026). Die
 * Leitlinie aus der Wissensbasis §7: "Grosse Momente gross behandeln, Routine
 * leise halten." Ein Dashboard ist Routine — die Bewegungen sind deshalb kurz,
 * einmalig und beim Betreten, nicht dauerhaft. Nichts pulsiert, nichts zappelt.
 *
 * Jede Animation hat ihren reduced-motion-Fallback (CLAUDE.md §9, Heuristik 9).
 * ========================================================================== */

/* ============================================================================
 * SEITENRAND
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Warum klemmt das alles so am Rand?"
 *
 * Weil `.container` (mordheim-theme.css) gar kein seitliches Polster hat. Ich
 * hatte ihm gestern nur die Safe Area gegeben — und die ist im Hochformat ohne
 * Notch schlicht 0. Fuer die alte Seite war das richtig (nichts veraendern),
 * fuer diese hier ist es zu wenig.
 *
 * Dasselbe Muster wie `.tc-page`, der kanonische Seiten-Container:
 * `max(24px, safe)` haelt immer mindestens 24px Abstand und weicht im
 * Querformat den Display-Rundungen aus. Unten zusaetzlich Platz fuer den
 * Home-Balken.
 *
 * Steht bewusst nur hier: dashboard-page.css wird ausschliesslich von der neuen
 * Seite geladen, die alte bleibt damit unberuehrt.
 * ========================================================================== */

.container.dash-page {
  padding-left: max(24px, var(--tc-safe-left, 0px));
  padding-right: max(24px, var(--tc-safe-right, 0px));
  padding-bottom: calc(32px + var(--tc-safe-bottom, 0px));
}

/* Auf schmalen Geraeten reichen 14px — 24px kosten dort spuerbar Inhalt.
 *
 * Das !important ist hier leider noetig und kein Schludrian: dashboard.css
 * setzt unter 900px `.container { padding: 0 !important }`, damit die alten
 * Karten am Handy randlos laufen. Gegen ein !important hilft nur ein
 * !important — die hoehere Spezifitaet von .container.dash-page allein reicht
 * nicht. Es wirkt ausschliesslich auf der neuen Seite, weil nur sie die
 * Klasse traegt und nur sie diese Datei laedt.
 * Faellt weg, sobald die alte Seite abgeloest ist. */
@media (max-width: 900px) {
  .container.dash-page {
    padding-left: max(14px, var(--tc-safe-left, 0px)) !important;
    padding-right: max(14px, var(--tc-safe-right, 0px)) !important;
  }
}

/* ============================================================================
 * SEKTIONEN — seit 14.08.2026 in css/components/dash-section.css
 * Der Rahmen wird auch von js/ui/werkbank.js im Untergrund ausgegeben und
 * musste deshalb aus der Seitendatei in eine Komponente (Umzug, keine Kopie).
 * Hier bleiben nur die .dash-page-Kontextregeln weiter unten.
 * ========================================================================== */

/* ============================================================================
 * TEASER-RASTER
 * Auto-fit statt fester Spaltenzahl: Das Raster entscheidet selbst, wie viele
 * Kacheln nebeneinander passen — vom Handy bis zum Schreibtisch ohne eigenen
 * Breakpoint. Genau der Bereich 769–900px, der sonst zwischen den Stuehlen
 * sitzt (Taskwerk #235), loest sich damit von allein.
 * ========================================================================== */

/* Eine Liste, kein Raster (13.08.2026). Der Wegweiser zeigt je System eine
   Zeile; ein auto-fit-Raster hatte hier nichts mehr zu verteilen. Die lange
   Begruendung zur alten Kachelbreite (320px-Boden, seitlicher Scroll bei
   320px Geraeten) ist mit dem Raster hinfaellig — Zeilen sind immer so breit
   wie ihr Container und koennen gar nicht ueberstehen. */
.dash-teaser-grid {
  display: flex;
  flex-direction: column;
  gap: var(--tc-space-2, 8px);
  /* Bezugsgroesse fuer die Systemzeilen. Sie richten sich danach, wie breit
     DIESES Raster ist — nicht danach, wie breit das Fenster ist. Begruendung
     im Kasten bei `@container dash-teaser` weiter unten. */
  container-type: inline-size;
  container-name: dash-teaser;
}

/* ============================================================================
 * DIE SYSTEM-ZEILE — der Wegweiser (13.08.2026)
 * ----------------------------------------------------------------------------
 * Hier stand bis heute die System-KACHEL: tc-hub__section als Rahmen,
 * tc-statcard-Raster fuer die Kennzahlen, tc-hub-shortcut als Weg in den Hub,
 * dazu ein <details>-Aufklapper fuer alles ab der fuenften Zahl.
 *
 * Tim zum Screenshot bei halber Seitenbreite: "Das ist noch etwas zu hoch.
 * Vielleicht lieber auf Zeilen gehen, als auf diese Kacheloptik?"
 *
 * Der Grund liegt tiefer als die Breite. Der Block ist ein WEGWEISER — seine
 * eigene Unterzeile sagt "Tiefe steckt im jeweiligen Hub". Mit tc-statcard war
 * er als Statistikseite gebaut: Diese Komponente traegt in einem Hub eine
 * ganze Bilanzzeile und ist rund 90px hoch. Fuenf Systeme mal bis zu fuenf
 * Karten sind eine Wand, und die Icon-Medaillons trugen dabei nichts bei
 * (Muskel fuer Machtfaktor, Balkendiagramm fuer S-U-N).
 *
 * Die Versionsgeschichte belegt es: acht Kennzahlen, dann vier plus
 * Aufklapper, dann ein Sonderfall fuer fuenf, dann "einen Aufklapper fuer eine
 * einzige Kachel gibt es nicht". Vier Korrekturen am Symptom, keine am Muster.
 *
 * Jetzt eine Zeile je System: links Marke, Mitte Kennzahlen als Fliesstext,
 * rechts der Weg hinein. Rund 60px statt rund 400px.
 *
 * MIT ENTFERNT, weil ohne Leser: .dash-sys (Kachelrahmen), .dash-sys__title,
 * .dash-sys__icon, .dash-sys__logo, .dash-sys__mehr* (der Aufklapper samt
 * drehendem Pfeil) und .dash-sys__link. Vor dem Loeschen gegen HTML und JS
 * geprueft. Geblieben sind .dash-sys__zocken* (der Knopf lebt weiter) und
 * die Animation dash-teaser-auf.
 * ========================================================================== */

.dash-sys-row {
  position: relative;          /* Bezug fuer den Stretched Link, s.u. */
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  flex-wrap: wrap;
  padding: var(--tc-space-2, 8px) var(--tc-space-3, 12px);
  /* Systemakzent als Kante — die Identitaet kommt aus dem System selbst
     (CLAUDE.md §9), alles andere aus den Seiten-Tokens. */
  border-left: 3px solid var(--teaser-accent, #a1917a);
  border-radius: var(--tc-radius-md, 8px);
  background: var(--tc-bg-surface-1, rgba(255, 255, 255, 0.03));
  animation: dash-teaser-auf 320ms ease-out backwards;
  animation-delay: var(--teaser-delay, 0ms);
}/* ============================================================================
 * DIE ZEILE WIRD EIN RASTER (16.08.2026)
 * ----------------------------------------------------------------------------
 * Tim: "Das hier ist inhaltlich okay, aber optisch und aus UX Gesichtspunkten
 * nicht gerade top."
 *
 * Ursache war `display: flex` mit `flex-wrap: wrap`. Die Breite der mittleren
 * Spalte richtete sich nach ihrem Inhalt — Mordheim hatte drei Kennzahlen,
 * Blood Bowl einen Satz, The Old World einen längeren. Damit begann jede Zeile
 * ihre Knöpfe an einer anderen Stelle, und bei The Old World reichte der Platz
 * nicht mehr: Die Aktionen brachen in eine zweite Zeile um und rissen ein Loch,
 * das aussah wie ein Fehler.
 *
 * Ein Raster mit festen Spuren löst beides auf einmal — die Spalten stehen in
 * allen Zeilen auf derselben Kante, und nichts kann mehr umbrechen.
 *
 * ⚠️ UND ES MUSS DIE CONTAINERBREITE SEIN, NICHT DIE DES FENSTERS
 * (20.08.2026). Hier stand `@media (min-width: 700px)` — gemessen wurde also
 * das Browserfenster. Das Raster liegt aber in der linken Dashboard-Spalte und
 * ist dort bei einem 1280px breiten Fenster nur **608px** breit. Die drei
 * Spuren (Marke 9,5rem | Text | Aktionen 1fr + 8,5rem) brauchen mehr: Der
 * Inhalt brach um, und die Zeilen wurden 88px hoch statt der 54, fuer die das
 * Raster gebaut wurde. Genau das hat Tim als „Text laeuft aus den
 * Klickflaechen" gesehen.
 *
 * `@container` fragt, was die Sache wirklich entscheidet — wie viel Platz
 * DIESES Raster hat. Ein Media Query kann das prinzipiell nicht wissen: Er
 * misst ein Fenster, in dem noch eine Seitenspalte, Raender und ein zweites
 * Raster stecken.
 *
 * Merksatz: Wenn ein Layout in einer Spalte lebt, ist die Fensterbreite die
 * falsche Frage.
 * ========================================================================== */
/* 480px: Das zweispaltige Raster (Marke | Aktionen) braucht deutlich weniger
   als die drei Spuren vorher. Gemessen am echten Container der linken
   Dashboard-Spalte — der ist bei einem 1280px-Fenster 608px breit, und mit
   der alten Schwelle von 620 fiel er um zwoelf Pixel durch. */
@container dash-teaser (min-width: 480px) {
  /* ⚠️ ZWEI SPUREN STATT DREI (20.08.2026). Vorher: Marke | Text | Aktionen
     mit `11.5rem minmax(0,1fr) 21rem` — zusammen mindestens 520px plus
     Luecken, in einem Container von 608px. Der mittlere Text wurde auf rund
     100px gequetscht, brach um und machte die Zeile 88px hoch statt der 54,
     fuer die das Raster gebaut war.

     Der Text war dabei das schwaechste Glied: „Roster, Chronik, Gefallene &
     Untergrund" beantwortet keine Frage, die man VOR dem Klick hat — der
     Hub-Link daneben sagt bereits „Zur Kriegsbande". Er steht deshalb jetzt
     als eigene, schmale Zeile UNTER der Marke, wo er die Hauptzeile nicht
     mehr verengt.

     Damit bleiben zwei Spuren: die Marke nimmt, was sie braucht, die
     Aktionen den Rest. */
  .dash-sys-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "marke aktionen"
      "sub   sub";
    align-items: center;
    row-gap: 2px;
  }

  .dash-sys-row__marke { grid-area: marke; }
  .dash-sys-row__aktionen { grid-area: aktionen; }
  /* Die Unterzeile: schmal, gedaempft, unter der Marke. Sie erklaert, was im
     Hub liegt — eine Fussnote, keine Spalte. `flex: 1 1 6rem` aus der
     Basisregel muss weg: Im Raster verlangt es Grundbreite fuer ein Element,
     das die ganze Zeile bekommt. */
  .dash-sys-row__sub {
    grid-area: sub;
    flex: none;
    font-size: 0.76rem;
    opacity: 0.85;
  }

  /* Die Statusmeldung („Noch keine Armeeliste eingereicht.") ist keine
     Fussnote — sie nennt den fehlenden Schritt und steht deshalb in voller
     Staerke da. */
  .dash-sys-row.is-ruft .dash-sys-row__sub { font-size: 0.82rem; opacity: 1; }

  /* Die Aktionen selbst ein zweites Raster, aus demselben Grund: „Jetzt zocken"
     nimmt den Rest, der Hub-Knopf bekommt eine feste Spur. Erst dadurch stehen
     auch die rechten Knoepfe untereinander auf einer Kante.

     ⚠️ DER SELEKTOR IST ABSICHTLICH ZWEITEILIG. Als blosses
     `.dash-sys-row__aktionen` (0,1,0) blieb die Regel WIRKUNGSLOS: Die
     Basisdefinition mit `display: flex` steht rund 70 Zeilen WEITER UNTEN in
     derselben Datei, hat dieselbe Spezifitaet — und die spaetere gewinnt.
     Gemessen: `display` blieb `flex`, obwohl hier `grid` steht. Das ist die
     Falle aus CLAUDE.md §10 ("beim Aendern fremder Bloecke ALLE treffenden
     Regeln auflisten, nicht nur die erste gefundene"), und sie faellt nicht
     auf, weil die Zeile trotzdem irgendwie aussieht. */
  .dash-sys-row .dash-sys-row__aktionen {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    justify-items: stretch;
    /* ⚠️ `margin-left: auto` MUSS WEG. Es steht in der Basisregel und war im
       Flex-Layout richtig (schiebt die Aktionen nach rechts). Im Raster
       bedeutet ein auto-Rand aber: Das Element schrumpft auf seinen INHALT und
       klebt rechts — es fuellt seine Spur nicht mehr aus. Gemessen: Zeilen mit
       kurzem Knopftext waren 301px breit statt 336, und damit begannen ihre
       Knoepfe 35px weiter rechts als in den anderen. Dieselbe Eigenschaft,
       zwei Layoutmodelle, gegenteilige Wirkung. */
    margin-left: 0;
  }

  /* Der Terminknopf fuellt seine Spur; der Hub-Link nimmt nur seinen Text.
     Beide auf volle Breite zu ziehen war die Optik, die sie wie zwei
     gleichwertige Knoepfe aussehen liess. */
  .dash-sys-row .dash-sys-row__aktionen > .dash-sys__zocken {
    width: 100%;
    justify-content: flex-start;
  }

  /* ⚠️ DER HUB-KNOPF WIRD FESTGENAGELT. Ohne diese Zeile rutscht er in die
     ERSTE Spur, sobald eine Zeile keinen „Jetzt zocken"-Knopf hat — dann steht
     er 80px weiter links als in allen anderen Zeilen. Ein Raster richtet nur
     aus, was man ihm zuweist; automatische Platzierung fuellt Luecken. */
  .dash-sys-row .dash-sys-row__hub { grid-column: 2; }
}

/* --- links: Logo + Name, feste Spur, damit die Zeilen untereinander
       auf einer Kante stehen. Kein eigener Link: Die ganze Zeile fuehrt
       ohnehin in den Hub (siehe __hub::after weiter unten), und zwei Links
       auf dasselbe Ziel sind fuer Screenreader eine Dopplung. --- */
.dash-sys-row__marke {
  display: inline-flex;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  flex: 0 0 auto;
  min-width: 9.5rem;
  color: var(--tc-text-strong, #eee);
}

/* ⚠️ ZWEIMAL AN DER FALSCHEN ZAHL GEDREHT (20.08.2026, Tim: "Die Logos kann
   man noch immer nicht lesen." — das „noch immer" ist der Hinweis).

   Am 16.08. ging die Box von 22 auf 38 px, und es half nicht. Der Grund steht
   in den Dateien: ALLE Logos sind breite Schriftzuege, keine Wappen.

       logo_aos.png        1523 x 383   = 4,0 : 1
       logo_bloodbowl.png   762 x 219   = 3,5 : 1
       logo_tow.png         756 x 220   = 3,4 : 1
       logo_mordheim.png   1052 x 354   = 3,0 : 1

   `width: 38px; height: 38px; object-fit: contain` presst so einen Schriftzug
   in ein QUADRAT: Die Breite begrenzt, die sichtbare Schrifthoehe ist ein
   Drittel bis ein Viertel davon — bei Age of Sigmar **9,5 px**. Eine groessere
   Box macht das Quadrat groesser, nicht die Schrift.

   Jetzt bestimmt die HOEHE die Darstellung und die Breite folgt dem
   Seitenverhaeltnis (28 px hoch ergibt 84-112 px breit). Damit ist der
   Schriftzug dreimal so hoch wie vorher, und die Markenspur traegt ihn.

   Merksatz: Bei `object-fit: contain` begrenzt IMMER die kleinere Seite. Wer
   ein 4:1-Bild in ein Quadrat legt, sieht ein Viertel. */
.dash-sys-row__logo {
  height: 28px;
  width: auto;
  max-width: 130px;
  object-fit: contain;
  object-position: left center;
  flex-shrink: 0;
}

.dash-sys-row__icon { font-size: 1.7rem; line-height: 1; }

.dash-sys-row__name {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: color 160ms ease;
}/* --- rechts: der Weg hinein --- */
.dash-sys-row__aktionen {
  display: flex;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  flex: 0 0 auto;
  margin-left: auto;
}

/* ⚠️ KEIN RAHMEN MEHR (20.08.2026). Mit Rahmen sah er aus wie ein zweiter,
   gleichwertiger Knopf neben „Jetzt zocken" — dabei ist er nur die sichtbare
   Beschriftung der ohnehin klickbaren Zeile (siehe __hub::after weiter
   unten). Zwei gleich aussehende Knoepfe, von denen einer in Wahrheit die
   ganze Flaeche meint, sind genau die Uneindeutigkeit, die Tim gemeldet hat.

   Der Rahmen bleibt als `transparent` stehen, damit die Hoehe gleich bleibt
   und beim Schweben/Fokus wieder auftauchen kann. */
.dash-sys-row__hub {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 var(--tc-space-3, 12px);
  min-height: var(--tc-touch-min, 36px);
  border: 1px solid transparent;
  border-radius: var(--tc-radius-md, 8px);
  color: var(--tc-text-default, #ddd);
  font-family: var(--tc-font-body, inherit);
  font-size: var(--tc-text-xs, 0.8rem);
  font-weight: var(--tc-weight-semibold, 600);
  white-space: nowrap;
  text-decoration: none;
  transition: color 160ms ease, border-color 160ms ease, background 160ms ease;
}

/* STRETCHED LINK — die ganze Zeile ist das Ziel.
   Tim: "Das soll mich ja in die Spielsysteme reinziehen." Ein Wegweiser, den
   man treffen MUSS, zieht niemanden; deshalb legt der Hub-Link eine
   unsichtbare Flaeche ueber die gesamte Zeile. Kein verschachteltes <a> —
   das waere ungueltiges Markup und fuer Screenreader ein Ratespiel. */
.dash-sys-row__hub::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.dash-sys-row:hover .dash-sys-row__hub,
.dash-sys-row__hub:focus-visible {
  border-color: var(--tc-border-subtle, rgba(255, 255, 255, 0.14));
  color: var(--tc-highlight, #d4c4a0);
  border-color: var(--tc-border-strong, rgba(255, 255, 255, 0.2));
  background: rgba(255, 255, 255, 0.04);
}
/* Die ganze Zeile reagiert mit, damit sichtbar ist, dass sie klickbar ist. */
.dash-sys-row:hover { background: var(--tc-bg-surface-2, rgba(255, 255, 255, 0.05)); }
/* Der Fokusring gehoert um die Zeile, nicht um den Link am Rand — er ist
   die tatsaechliche Trefferflaeche. */
.dash-sys-row:has(.dash-sys-row__hub:focus-visible) {
  outline: 2px solid var(--tc-highlight, #d4c4a0);
  outline-offset: 2px;
}
.dash-sys-row__hub:focus-visible { outline: none; }

/* "Jetzt zocken" fuehrt an den Tisch, nicht in den Hub — es muss ueber der
   Zeilenflaeche liegen, sonst schluckt der Stretched Link den Klick. */
.dash-sys-row__aktionen .dash-sys__zocken {
  position: relative;
  z-index: 1;
  /* Kompakter als in der alten Kachel: Dort war der Knopf das Hauptangebot
     einer 400px hohen Flaeche und durfte 44px hoch sein. In einer Zeile
     bestimmt er die Zeilenhoehe — bei 776px Spaltenbreite rutschen die
     Wege ohnehin in eine zweite Zeile, und die war dadurch 56px hoch.
     36px ist weiterhin das Touch-Mass dieser Seite (Heuristik 5). */
  min-height: var(--tc-touch-min, 36px);
  padding: 0 var(--tc-space-3, 12px);
}
.dash-sys-row__aktionen .dash-sys__zocken-icon { font-size: 1rem; }
/* Der Pfeil am Knopf ist neben dem Pfeil des Hub-Links eine Wiederholung —
   zwei Wegweiser nebeneinander zeigen nicht besser. */
.dash-sys-row__aktionen .dash-sys__zocken-pfeil { display: none; }

/* AM HANDY (bis 560px)
   -----------------------------------------------------------------------
   Drei Eingriffe, alle gegen dieselbe Zahl: Eine Zeile war hier zuerst
   188px hoch — das ist keine Zeile mehr, sondern wieder eine Kachel.
   Gemessen bei 375px, also 343px nutzbarer Breite.

   1. NUR ZWEI KENNZAHLEN. Die dritte bricht ohnehin um und kostet eine
      volle Zeile. Welche das ist, entscheidet die Reihenfolge im JS —
      dort steht das Wichtigste vorn. Bewusst in CSS und nicht ueber eine
      matchMedia-Abfrage beim Zeichnen: Die wurde einmal ausgewertet und
      stimmte nach dem Drehen des Geraets nicht mehr.

   2. DIE WEGE IN EINE ZEILE. Gestapelt kosteten sie 82px. "Jetzt zocken"
      nimmt den Platz, der Hub-Weg schrumpft auf sein Zeichen — er darf
      das, weil die GANZE ZEILE ohnehin in den Hub fuehrt (Stretched Link
      weiter oben) und der Systemname daneben sagt, wohin. Die
      Beschriftung bleibt fuer Screenreader im Markup.

   3. Ein zu langer Termin wird gekuerzt statt herauszuragen; der volle
      Text steht im title-Attribut des Knopfes. */
@media (max-width: 560px) {
  .dash-sys-row__fakt:nth-child(n+3) { display: none; }

  .dash-sys-row__aktionen {
    margin-left: 0;
    width: 100%;
    flex-wrap: nowrap;
  }
  .dash-sys-row__aktionen .dash-sys__zocken {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
  }
  .dash-sys-row__hub {
    flex: 0 0 auto;
    justify-content: center;
    min-width: var(--tc-touch-min, 36px);
    padding: 0 10px;
  }
  /* Nur das Zeichen — der Name des Ziels waere hier der teuerste Text der
     Zeile. Fuer Screenreader bleibt er ueber .tc-sr-only erhalten. */
  .dash-sys-row__hub { font-size: 0; }
  .dash-sys-row__hub [aria-hidden="true"] { font-size: 1.2rem; }

  .dash-sys__zocken-text { overflow: hidden; }
  .dash-sys__zocken-wann { min-width: 0; }
}


/* Bandennamen sind Text, keine Messgroesse: kleiner, ohne feste Ziffernbreite,
   und sie duerfen umbrechen statt die Kachel zu sprengen. */
/* KORRIGIERT am 12.08.2026: Hier stand `overflow-wrap: anywhere`. In einer
   88px schmalen Rasterspalte zerlegt das den Bandennamen buchstabenweise in
   eine Senkrechte ("G-o-r-p-o-r-a-t-i-o-n"). `break-word` bricht nur dann
   innerhalb eines Wortes, wenn es allein nicht in die Zeile passt.
   Denselben Fehler hatte ich schon einmal am Label ("SCHATTENGOL / D") —
   er stand nur noch am Wert. */
.tc-statcard__value.is-text {
  font-size: 0.95rem;
  font-variant-numeric: normal;
  line-height: 1.25;
  overflow-wrap: break-word;
  hyphens: auto;
}

/* Gleiche Ziffernbreite waehrend des Hochzaehlens — sonst zappelt die Zahl,
   weil eine 1 schmaler ist als eine 8. */
.dash-teaser__num {
  font-variant-numeric: tabular-nums;
}

.tc-empty-state--inline {
  padding: var(--tc-space-3, 12px) 0;
  font-style: italic;
  color: var(--tc-text-muted, #888);
}

/* ============================================================================
 * DAS SAISONBAND — in der Blaetterzeile des Ausrufers (13.08.2026)
 * ----------------------------------------------------------------------------
 * Tim, mit Screenshot der Zeile "‹ 2 / 40 ›": "Ne, mach den Balken mal hier
 * neben:"
 *
 * Der richtige Ort, und nicht nur wegen des Platzes: In dieser Zeile steht
 * bereits eine Standanzeige — wo bin ich in den Meldungen. Daneben gehoert
 * die zweite: wo bin ich in der Saison. Zwei Zeilen untereinander waeren
 * zweimal dasselbe Moebel.
 *
 * Die Zeile liegt auf dem Bannerbild. Deshalb kein Kartengrund, sondern ein
 * dunkler Schleier mit Weichzeichner (ein undurchsichtiger Kasten waere ein
 * Loch im Bild) und Schrift mit Schatten, wie Titel und Ausruf daneben —
 * auf einem Foto traegt Farbe allein nicht (CLAUDE.md §9).
 *
 * Der Balken ist verrinnende Zeit, kein eigener Fortschritt. Er laeuft vom
 * Akzent ins Warme: je weiter die Saison, desto naeher die Schmelze, bei der
 * das Schattengold auf ein Zehntel faellt.
 * ========================================================================== */

/* Die Blaetterzeile traegt jetzt zwei Dinge und darf dafuer umbrechen. */
.dash-buehne__nav { flex-wrap: wrap; justify-content: center; }

.dash-saison {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  /* Abstand zur Blaetter-Navigation, ohne eigene Zeile zu beanspruchen. */
  margin-left: var(--tc-space-2, 8px);
  padding: 5px 12px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.42);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
  line-height: 1;
}
.dash-saison:empty { display: none; }

.dash-saison__icon { font-size: 0.95rem; line-height: 1; }

.dash-saison__name {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--tc-highlight, #d4c4a0);
  white-space: nowrap;
}

.dash-saison__balken {
  flex: 0 0 auto;
  width: 6.5rem;
  height: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  overflow: hidden;
}
.dash-saison__fuellung {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg,
              var(--tc-accent, #8b0000) 0%,
              var(--tc-highlight, #d4c4a0) 100%);
}

.dash-saison__rest {
  font-size: var(--tc-text-2xs, 0.72rem);
  color: rgba(255, 255, 255, 0.75);
  white-space: nowrap;
}

/* Die letzten zwei Wochen: der Resttext wird warm. Kein Ausrufezeichen und
   keine Warnfarbe — eine Temperatur, die auffaellt, ohne zu erschrecken.
   Gesetzt vom JS ueber .ist-knapp. */
.dash-saison__rest.ist-knapp { color: var(--tc-highlight, #d4c4a0); font-weight: 600; }

/* Die Zahl der Saison-Erfolge braucht in dieser Zeile keinen Platz — sie
   steht im Fortschritts-Abschnitt ohnehin ausfuehrlicher. Fuer
   Screenreader bleibt sie im Markup. */
.dash-saison__erfolge { position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Am Handy faellt der Balken weg: Neben Pfeilen und Zaehler blieben ihm
   keine 40px, und ein Balken, den man nicht lesen kann, ist Dekoration.
   Die Tageszahl daneben sagt dasselbe genauer. */
@media (max-width: 560px) {
  .dash-saison { margin-left: 0; padding: 4px 10px; gap: 7px; }
  .dash-saison__balken { display: none; }
}

/* ============================================================================
 * REDUCED MOTION — Pflicht nach CLAUDE.md §9
 * ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .dash-sys-row,
  .dash-sys-row__hub {
    animation: none;
    transition: none;
  }
  .dash-teaser-skeleton { animation: none; }
}

/* ============================================================================
 * EINBLENDEN + PLATZHALTER
 * Die Sektionen kommen leicht versetzt herein (--teaser-delay je Sektion).
 * Insgesamt unter einer halben Sekunde, und genau einmal.
 * ========================================================================== */

@keyframes dash-teaser-auf {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Platzhalter, solange die Daten noch nicht stehen: ein ruhiger Schimmer
   statt eines Spinners. Die Seite behaelt ihre Form, es springt nichts. */
.dash-teaser-skeleton {
  min-height: 148px;
  border-radius: var(--tc-radius-lg, 12px);
  border: 1px solid rgba(255, 255, 255, 0.05);
  background: linear-gradient(100deg,
    rgba(255, 255, 255, 0.02) 30%,
    rgba(255, 255, 255, 0.055) 50%,
    rgba(255, 255, 255, 0.02) 70%);
  background-size: 200% 100%;
  animation: dash-skeleton 1.4s ease-in-out infinite;
}

@keyframes dash-skeleton {
  from { background-position: 140% 0; }
  to   { background-position: -40% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .dash-sys-row { animation: none; }
  .dash-teaser-skeleton { animation: none; }
}

/* ============================================================================
 * MOBIL
 * ========================================================================== */

@media (max-width: 600px) {
  .dash-teaser-grid { grid-template-columns: 1fr; }
}

/* ============================================================================
 * RANGLISTEN — drei nebeneinander statt einer Liste mit Untermenue
 * Die alte Rangliste hatte eine Navigationsspalte mit zehn Eintraegen, aus
 * der man einen auswaehlte. Bei drei Kategorien lohnt das nicht — alle drei
 * passen nebeneinander und sind ohne Klick lesbar ("auf einen Blick sichtbar",
 * Wissensbasis §4.1).
 * ========================================================================== */

.dash-rl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--tc-space-3, 12px);
}/* ============================================================================
 * MEIN FORTSCHRITT
 * Rang gross oben, Kennzahlen als tc-statcard, XP-Bahn, Vitrine.
 * Der Rang ist das, was man herzeigt — die Zahlen sind die Mechanik dahinter.
 * ========================================================================== */

.dash-fortschritt__rang {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  margin-bottom: var(--tc-space-4, 16px);
}

.dash-fortschritt__rang-icon {
  font-size: 2rem;
  line-height: 1;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.55));
}

.dash-fortschritt__rang-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.dash-fortschritt__rang-name {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--tc-highlight, #d4c4a0);
  line-height: 1.15;
}

.dash-fortschritt__rang-titel {
  font-size: 0.82rem;
  font-style: italic;
  color: var(--tc-text-muted, #999);
}

/* XP-Bahn zum naechsten Rang */
/* Der XP-Balken liegt seit dem 20.08.2026 in css/components/xp-bar.css als
   `tc-xp-bar` — er steht jetzt auch im oeffentlichen Spielerprofil. Hier
   bleibt nur, was diese Seite eigen macht. */
.dash-fortschritt__xp {
  margin-top: var(--tc-space-4, 16px);
}


/* „Fast geschafft" (#311) — die Liste selbst ist die Library-Komponente
   `tc-ach-near` (components/ach-near.css). Hier steht nur, wie der Block in
   dieser Seite sitzt. */
.dash-fortschritt__nah {
  margin-top: var(--tc-space-4, 16px);
  padding-top: var(--tc-space-3, 12px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.dash-fortschritt__nah-titel {
  margin: 0 0 var(--tc-space-2, 8px);
  font-family: var(--tc-font-body, sans-serif);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tc-text-muted, #9e9e9e);
}

.dash-fortschritt__vitrine {
  margin-top: var(--tc-space-4, 16px);
  padding-top: var(--tc-space-3, 12px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

@media (prefers-reduced-motion: reduce) {
}

/* ----------------------------------------------------------------------------
 * ZWEISPALTIG: Fortschritt links, Untergrund rechts
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Der Part laeuft mir zu weit. Da reichen 50% des Screens.
 * Dann kann daneben der Untergrund angeteasert werden."
 *
 * 1000px ist der Umschaltpunkt, nicht 768: Bei 1600px Seitenbreite ergeben
 * zwei Spalten je ~780px; darunter wird die Fortschritts-Spalte so schmal,
 * dass die drei tc-statcards (minmax 148px) auf eine Spalte umbrechen und
 * der Block hoeher wird als er breit ist.
 *
 * `align-items: start` ist Absicht: Die beiden Kacheln sind unterschiedlich
 * hoch, und eine gestreckte Untergrund-Kachel mit Leerraum unten saehe aus
 * wie ein Ladefehler. -------------------------------------------------------- */

/* Zwei gleich breite Spalten, ab 1000px nebeneinander, darunter gestapelt.
 *
 * Hiess bis zum 13.08.2026 nur `.dash-progress-split` und war fuer
 * Fortschritt/Untergrund gedacht. Dann kam dieselbe Ansage ein zweites Mal,
 * fuer "Meine Spiele" und den Ausrufer-Abschnitt (Tim: "Setz mal beides auf
 * 50% Breite, nicht 100%") — also bekommt das Muster einen allgemeinen Namen.
 *
 * Der alte Selektor bleibt daneben stehen, statt ihn zu ersetzen: Er steht
 * noch im Markup, und ein Rename in zwei Dateien gleichzeitig ist genau die
 * Gelegenheit, bei der eine Haelfte liegenbleibt (CLAUDE.md, "Eine Klasse
 * migrieren heisst: ihre Kontextregeln mitnehmen").
 *
 * `align-items: start` ist wichtig: Ohne das zoegen sich beide Spalten auf
 * die Hoehe der laengeren — der Ausrufer-Abschnitt ist mal kurz und mal
 * lang, und "Meine Spiele" wuerde jedes Mal mitwachsen. */
/* ============================================================================
 * ZWEI SPALTEN, DIE FLIESSEN (20.08.2026, Taskwerk-Rueckfrage Tim)
 * ----------------------------------------------------------------------------
 * Tim: „Hast du hier die 2-Spalten Logik korrekt implementiert? Oder sind die
 * Content-Teaserboxen weiter nach Spalten ausgerichtet?"
 *
 * Sie waren nach ZEILEN ausgerichtet. Jedes Paar war eine eigene Rasterzeile,
 * und eine Rasterzeile ist so hoch wie ihre laengere Haelfte — darunter blieb
 * ein Loch, das kein Inhalt fuellen konnte, und das naechste Paar begann erst
 * danach. Gemessen am 20.08.2026: Fortschritt 813px gegen Untergrund 406px.
 *
 * Jetzt zwei Flex-Spalten. Jeder Block beginnt direkt unter seinem Vorgaenger
 * IN SEINER SPALTE. Das ist der Unterschied zwischen „nebeneinander" und
 * „in Spalten": Ersteres richtet paarweise aus, Letzteres laesst fliessen.
 *
 * ⚠️ `align-items: flex-start` ist Pflicht. Ohne das zoegen sich die beiden
 * Spalten gegenseitig auf dieselbe Hoehe, und der Kasten am Fuss der kuerzeren
 * Spalte waere wieder gestreckt — genau das, was Tim gemeldet hat.
 *
 * ⚠️ UNTER 1000px ENTSCHEIDET `order`, NICHT DIE DOM-REIHENFOLGE. Die Seiten
 * werden dort zu `display: contents`; ohne die acht `order`-Regeln stuende am
 * Handy erst die ganze linke Spalte (Fortschritt, Meine Spiele, Werkstatt,
 * Werkbank) und danach die ganze rechte — die Ranglisten kaemen dann direkt
 * nach der Werkbank statt am Schluss, und der Untergrund erst nach vier
 * Bloecken statt gleich nach dem Fortschritt.
 * Die Grundstellung `order: 20` faengt einen neunten Block ab: Ohne sie haette
 * er `order: 0` und stuende ploetzlich ganz oben.
 * ========================================================================== */
.dash-spalten {
  display: flex;
  flex-direction: column;
  gap: var(--tc-space-4, 16px);
}

.dash-spalten__seite { display: contents; }
.dash-spalten__seite > * { order: 20; }

.dash-spalten__seite--links  > :nth-child(1) { order: 1; }
.dash-spalten__seite--rechts > :nth-child(1) { order: 2; }
.dash-spalten__seite--links  > :nth-child(2) { order: 3; }
.dash-spalten__seite--rechts > :nth-child(2) { order: 4; }
.dash-spalten__seite--links  > :nth-child(3) { order: 5; }
.dash-spalten__seite--rechts > :nth-child(3) { order: 6; }
.dash-spalten__seite--links  > :nth-child(4) { order: 7; }
.dash-spalten__seite--rechts > :nth-child(4) { order: 8; }

@media (min-width: 1000px) {
  .dash-spalten {
    flex-direction: row;
    align-items: flex-start;
  }

  .dash-spalten__seite {
    display: flex;
    flex-direction: column;
    gap: var(--tc-space-4, 16px);
    flex: 1 1 0;
    /* Ohne `min-width: 0` sprengt ein breiter Inhalt (Bilderreihe, lange
       Tabellenzeile) die Spalte, statt in ihr zu bleiben. */
    min-width: 0;
  }

  /* Innerhalb der Spalten gilt `order` nicht mehr — dort steht alles in
     DOM-Reihenfolge, und die ist je Spalte bereits die richtige. */
  .dash-spalten__seite > * { order: 0; }
}

.dash-split,
.dash-progress-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--tc-space-4, 16px);
  align-items: start;
}

@media (min-width: 1000px) {
  .dash-split,
  .dash-progress-split { grid-template-columns: 1fr 1fr; }
}

/* ----------------------------------------------------------------------------
 * ZWEI PAARE ZIEHEN GLEICH — Tim, 16.08.2026
 * ----------------------------------------------------------------------------
 * "Kannst du links die Darstellung der Achievements so anpassen, dass der linke
 * Block in der Hoehe zum Untergrund passt? Das gleiche gilt fuer die Galerie
 * weiter unten."
 *
 * `align-items: start` darueber bleibt der RICHTIGE Standard — die Begruendung
 * eine Regel hoeher gilt unveraendert fuer Ausrufer/Meine Spiele und den
 * Hub-Fuss, wo die eine Seite mal kurz und mal lang ist. Hier sind es dagegen
 * zwei Bloecke mit fester Gliederung, die nebeneinander wie eine Doppelseite
 * gelesen werden; eine kuerzere Haelfte sieht dort nach abgeschnitten aus.
 *
 * ⚠️ STRECKEN ALLEIN WAERE EINE VERSCHLIMMBESSERUNG. Ein gestreckter Kasten mit
 * dem Inhalt oben und Leere unten sieht kaputter aus als der kurze Kasten
 * vorher. Deshalb zwei Schritte:
 *   1. Die Spalte streckt sich (`stretch`) und reicht die Hoehe durch — der
 *      Wrapper zwischen Raster und Karte (`#dashProgress` usw.) muss dafuer
 *      selbst Flex sein, sonst endet die Hoehe bei ihm.
 *   2. Die Karte verteilt: Kopf und Zahlen oben, der FUSS unten
 *      (`margin-top: auto`). Der Fuss ist bei jedem der vier Bloecke das
 *      Element, das unten stehen darf — die Achievement-Vitrine, der
 *      Hinabsteigen-Knopf, der Galerie-Hinweis, der Baustellen-Satz.
 *
 * Das wirkt in BEIDE Richtungen: Es ist nicht festgelegt, welche Haelfte die
 * laengere ist. Ohne Muenzschmelze-Leiste ist der Untergrund kuerzer als der
 * Fortschritt (lokal gemessen 423 zu 417), mit ihr deutlich laenger. Eine
 * Regel, die nur den heute laengeren Block kennt, waere in vier Wochen falsch.
 * ------------------------------------------------------------------------- */
/* ⚠️ `.dash-progress-split` IST HIER RAUSGEFALLEN (20.08.2026, Tim: „Die Box
 * ist cool, aber stretcht den Untergrund extrem nach unten.").
 *
 * Die Doppelseiten-Logik oben war fuer zwei etwa gleich hohe Haelften
 * geschrieben — am 16.08. gemessen 423 zu 417. Mit „Fast geschafft" (#311)
 * sind es 813 zu 406: Die linke Spalte traegt jetzt doppelt so viel Inhalt.
 * Gestreckt heisst das 407px Leere unter dem Hinabsteigen-Knopf, und genau
 * davor warnt der Kasten oben selbst („Ein gestreckter Kasten mit dem Inhalt
 * oben und Leere unten sieht kaputter aus als der kurze Kasten vorher").
 *
 * CSS kann „strecken, solange der Unterschied klein ist" nicht ausdruecken.
 * Also gilt fuer dieses Paar wieder `align-items: start` von weiter oben —
 * der Untergrund behaelt seine natuerliche Hoehe. Fuer die Werkstatt-Zeile
 * bleibt die Streckung: Dort sind die beiden Haelften weiterhin aehnlich. */
@media (min-width: 1000px) {
  .dash-split--werkstatt { align-items: stretch; }

  /* Die Hoehe durch den Wrapper durchreichen. `#dashProgress` und
     `#dashUntergrund` sind blanke <div>s ohne eigene Gestaltung — ohne diese
     Zeile streckt sich der Wrapper, die Karte darin bleibt kurz. */
  .dash-split--werkstatt > .dash-section {
    display: flex;
    flex-direction: column;
  }

  /* Der jeweilige Fuss wandert nach unten, statt dass darunter Leere klafft. */
  .dash-untergrund__fuss,
  .wt-fuss { margin-top: auto; }

  /* ⚠️ DIE VITRINE STAND HIER AUCH — UND DAS WAR FALSCH (Tim, 16.08.2026:
   * "bei 'Mein Fortschritt' hast du jetzt ne EP Leiste mit viel Abstand
   * reingepackt, aber die Achievements sind noch gleich klein unten drunter.
   * Fokus bitte.").
   *
   * `margin-top: auto` hat die Vitrine nach unten geschoben und den gewonnenen
   * Platz als LUECKE ueber ihr gelassen — genau das, was ich mit der Regel
   * verhindern wollte. Der Fehler steckt in der Annahme: Ich habe die Vitrine
   * fuer eine Fusszeile gehalten. Sie ist aber der INHALT, auf den der Block
   * hinauslaeuft, und ein Inhalt gehoert nicht ans Ende geschoben, sondern
   * vergroessert.
   *
   * Deshalb waechst sie jetzt (`flex: 1`) und ihre Kacheln mit ihr. */
  /* ⚠️ ZWEITER ANLAUF, UND DER ERSTE WAR AUCH FALSCH (Tim, 16.08.2026:
   * "Ne, jetzt ziehst du den Untergrund unnötig in die Höhe. Die Achievements
   * sollen in einer Zeile nebeneinander stehen. inkl. einem Teaser auf mehr.
   * Wie bei den Terminen oben.").
   *
   * Erst habe ich die Vitrine nach unten geschoben (Luecke darueber), dann auf
   * zwei mal zwei gestellt — und damit den Block so hoch gemacht, dass der
   * gestreckte Untergrund daneben unten 200px Leere zeigte. Beide Male habe ich
   * die HOEHE als Stellschraube benutzt; richtig ist die BREITE. Die Spalte ist
   * rund 950px breit, fuenf Kacheln nebeneinander sind darin je etwa 180px —
   * groesser als in der 2×2-Fassung UND nur eine Reihe hoch.
   *
   * Fuenf, nicht vier: Die letzte ist der Absprung in die Uebersicht, nach dem
   * Vorbild der vierten Terminkarte (`event-card-more`).
   *
   * Und der Block verteilt seine Hoehe jetzt ueber `space-between` statt ueber
   * eine wachsende Vitrine — so fuellt er die Spalte, ohne sie vorzugeben. */
  /* `justify-content: space-between` stand hier fuer den gestreckten
     Fortschritt. Ohne Streckung gibt es nichts zu verteilen — die Regel waere
     ab jetzt eine, die aussieht, als taete sie etwas. */

  .dash-fortschritt__vitrine .ach-showcase {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    max-width: none;
  }

  /* Der 76px-Deckel der Komponente faellt nur hier — auf der Profilseite ist
     die schmale Reihe weiterhin richtig. */
  .dash-fortschritt__vitrine .ach-showcase-item .tc-ach-tile { max-width: none; }

  .dash-fortschritt__vitrine .ach-showcase-item__name { font-size: 0.75rem; }

  /* `.wt-leer` steht BEWUSST NICHT in der Liste darueber. Es ist keine
     Fusszeile, sondern die Auskunft "hier ist noch nichts" — und die gehoert
     unter die Ueberschrift, auf die sie sich bezieht. Nach unten geschoben
     stuende sie unter einer leeren Flaeche und saehe aus, als fehlte darueber
     etwas. */

  /* ⚠️ DIE GALERIE HAT SICH NICHT VERAENDERT, und Tim hat das gesehen
   * ("Und die Darstellung der Werkstatt im Dashboard hat sich noch gar nicht
   * geändert."). Zu Recht: Gemessen waren die beiden Kaesten mit 283px schon
   * vorher gleich hoch — der Kasten war nie das Problem. Meine Regel hat also
   * etwas repariert, das nicht kaputt war, und das eigentliche gelassen.
   *
   * Das eigentliche ist die Kachelgroesse: `minmax(96px, 1fr)` mit `auto-fill`
   * stellt in einer halben Spalte vier Bilder von je 96px nebeneinander. Ein
   * bemaltes Modell ist auf 96px ein Fleck. Zwei Spalten machen daraus rund
   * 165px — man erkennt, was da steht, und die zweite Reihe fuellt die Hoehe.
   *
   * `auto-fit` statt `auto-fill`: Bei nur zwei Bildern sollen sie die Breite
   * nehmen statt eine leere dritte Spur stehen zu lassen. Die Begruendung fuer
   * `auto-fill` in der Komponente galt fuer eine breite Reihe, nicht fuer zwei
   * Spalten. */
  .dash-split--werkstatt .wt-bilder {
    flex: 1;
    align-content: start;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  }
}

/* Der Ausrufer-Abschnitt steht jetzt in einer halben Spalte. Der Knopf
   darunter braucht Abstand zum Feed, sonst klebt er an der letzten Meldung. */
.dash-split .dash-buehne__archiv-mehr { margin-top: var(--tc-space-3, 12px); }

/* --- Der Fuss der System-Hubs: Ausrufer links, Untergrund rechts ---
 * (14.08.2026, Tims zweite Option statt eines zweiten Berichts.)
 *
 * Beide beginnen oben statt sich auf gleiche Hoehe zu strecken — der
 * Bericht ist mal kurz, mal lang, der Untergrund immer gleich hoch. Ein
 * gestreckter Bericht mit Leerraum darunter saehe nach Fehler aus.
 *
 * Und Luft nach oben: Der Fuss folgt auf den Hub-Inhalt und braucht die
 * gleiche Zaesur, die `.tc-hub` zwischen seinen Abschnitten setzt. */
.dash-split--fuss {
  align-items: start;
  margin-top: var(--tc-space-6, 24px);
}

/* ----------------------------------------------------------------------------
 * DER UNTERGRUND — Vorbote, kein Rohbau
 * ----------------------------------------------------------------------------
 * Grundlage: SCHATTENGOLD-V2-BRIEFING §7.2 (kompaktes SG-Widget im Dashboard)
 * und §7.1 (Untergrund = eigenes Theme, duester/schattig).
 *
 * Die Kachel zieht ihre Farben bewusst NICHT aus dem aktiven System-Theme:
 * Der Untergrund ist laut Briefing das siebte "System" mit eigener Anmutung,
 * und er soll sich neben dem Fortschritt auch sichtbar anders anfuehlen.
 * Der Akzent bleibt dennoch --tc-highlight, damit die Kachel nicht wie ein
 * Fremdkoerper von einer anderen Seite wirkt. ------------------------------- */

/* Die Kachel ist eine TÜR, kein Kasten (13.08.2026, Tims Anmerkung: „sieht
   gar nicht so aus wie der fertige Unterbereich").
   Sie zeigt dasselbe Gewölbe wie untergrund.html und trägt DESSEN Farben —
   auch auf einem Dashboard, das gerade im Mordheim-, BB- oder ToW-Theme
   steht. Das ist die bewusste Ausnahme von „Akzent kommt aus dem Theme"
   (CLAUDE.md §9): Der Untergrund ist ein anderer Ort, und genau das soll man
   sehen. Deshalb eigene Variablen statt --tc-accent. */
.dash-untergrund {
  --ug-bernstein:       #c0782e;
  --ug-bernstein-hell:  #e09a4a;
  --ug-gold:            #e8cf9a;
  --ug-bernstein-rgb:   192, 120, 46;

  position: relative;
  overflow: hidden;
  border: 1px solid rgba(var(--ug-bernstein-rgb), 0.35);

  /* RADIUS UND INNENABSTAND (14.08.2026, Tim: "bitte auch mit abgerundeten
   * Ecken, wie alles andere auch. Padding bzw. Abstände zum Rand einbauen,
   * aktuell klebt alles am Rand.")
   *
   * Beides fehlte hier ganz. Auf dem Dashboard fiel es nicht auf, weil dort
   * `.dash-page .tc-hub__section` 16px Innenabstand mitgab — und `.dash-page`
   * gibt es in KEINEM der vier Hubs. Der Block stand dort also randlos.
   * Das ist die Falle aus CLAUDE.md §10/2 in ihrer Umkehrung: Eine Regel
   * greift nur dort, wo eine Elternklasse vorkommt, die man auf der anderen
   * Seite nicht mitgedacht hat.
   *
   * Die Werte kommen vom Nachbarn: tc-panel hat 16px Radius
   * (--tc-radius-xl) und seitlich 20px Innenabstand (panel.css:35/98).
   * Gleiche Optik, gleiche Werte — nicht geschaetzt, nachgemessen.
   *
   * SCHRIFT: Der Block ist auf mordheim-hub.html, aos.html und oldworld.html
   * der einzige Seitenblock AUSSERHALB von `.tc-hub`, und `.tc-hub` ist es,
   * die dort die Schrift setzt (hub.css:18). `body` traegt auf diesen drei
   * Seiten gar keine font-family — der ganze Untergrund-Block lief also in
   * Times. Genau der Fall, vor dem CLAUDE.md §9 warnt ("wer auf Vererbung
   * hofft, bekommt Times"). Deshalb setzt er sie jetzt selbst. */
  border-radius: var(--tc-radius-xl, 16px);
  font-family: var(--tc-font-body, Lato, 'Segoe UI', system-ui, sans-serif);
}

/* Der Innenabstand steht mit BEIDEN Klassen (0,2,0), weil auf dem Dashboard
   `.dash-page .tc-hub__section` mit derselben Spezifitaet 16px ringsum setzt
   und sonst gewinnen wuerde — der Block saehe auf dem Dashboard anders aus
   als in den Hubs. Beide Renderer setzen beide Klassen (dashboard-teaser.js:899,
   untergrund-teaser.js:103), der Selektor trifft also immer. */
.dash-untergrund.tc-hub__section {
  padding: var(--tc-space-4, 16px) var(--tc-space-5, 20px);
  background:
    /* Der Lichtkreis der Laterne, oben links wie im Bild */
    radial-gradient(90% 70% at 18% 0%, rgba(var(--ug-bernstein-rgb), 0.22), transparent 62%),
    /* Der Vorhang, der den Text lesbar hält — ohne ihn läge Schrift auf Stein.
       Die Mitte ist am dunkelsten, weil dort der Ausrufer-Text und die
       Wirte-Liste liegen; oben darf das Gewölbe durchkommen, unten trägt der
       Knopf sich selbst. Heuristik 8: Lesbarkeit gewinnt vor Dekor. */
    linear-gradient(180deg, rgba(10, 8, 6, 0.62) 0%, rgba(10, 8, 6, 0.93) 42%, rgba(8, 6, 4, 0.96) 100%),
    url('../assets/schattenmarkt/schattenmarkt.webp') 50% 38% / cover no-repeat,
    linear-gradient(180deg, #14100c, #0d0a07);
}

/* Ein warmer Schimmer an der Oberkante — als läge Licht auf der Türschwelle. */
.dash-untergrund::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--ug-bernstein-hell), transparent);
  opacity: 0.7;
}

/* Ein schmaler Lichtschein oben — das einzige Dekor. Er deutet an, dass da
   unten etwas ist, ohne dass es ein Bild braucht (es gibt noch keines). */
.dash-untergrund::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: linear-gradient(90deg,
              transparent,
              var(--tc-highlight, #d4c4a0),
              transparent);
  opacity: 0.5;
  pointer-events: none;
}

.dash-untergrund__kopf {
  display: flex;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  margin-bottom: var(--tc-space-4, 16px);
}

.dash-untergrund__titel {
  margin: 0;
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--tc-highlight, #d4c4a0);
  letter-spacing: 0.02em;
}

/* "Bald" statt "Coming Soon": Die Marke sagt ehrlich, dass hier nichts
   anklickbar ist — sonst sucht man den Eingang und findet keinen. */
.dash-untergrund__marke {
  flex-shrink: 0;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tc-highlight, #d4c4a0);
  background: rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.12);
  border: 1px solid rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.3);
}

/* Der Kontostand — der einzige echte Wert in dieser Kachel. */
.dash-untergrund__kasse {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  padding: var(--tc-space-3, 12px);
  border-radius: var(--tc-radius-lg, 12px);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.dash-untergrund__muenze {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: var(--tc-radius-md, 8px);
  display: grid;
  place-items: center;
  font-size: 1.1rem;
  background: radial-gradient(circle at 30% 25%,
              rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.25),
              rgba(0, 0, 0, 0.35));
  border: 1px solid rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.3);
}

.dash-untergrund__kasse-text { display: flex; flex-direction: column; min-width: 0; }

.dash-untergrund__kasse-wert {
  font-weight: 700;
  font-size: 1.7rem;
  line-height: 1;
  color: var(--tc-highlight, #d4c4a0);
  font-variant-numeric: tabular-nums;
}

.dash-untergrund__kasse-label {
  margin-top: 3px;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tc-text-muted, #999);
}

/* Der Ausrufer spricht — Briefing §7.1: Aussenstimme ist immer der Cryer. */
.dash-untergrund__ruf {
  margin: var(--tc-space-4, 16px) 0 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--tc-text-default, #ddd);
}

.dash-untergrund__ruf-wer {
  display: block;
  margin-bottom: 2px;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tc-highlight, #a1917a);
}

.dash-untergrund__ruf-text { font-style: italic; }

.dash-untergrund__haeuser {
  list-style: none;
  margin: var(--tc-space-4, 16px) 0 0;
  padding: var(--tc-space-3, 12px) 0 0;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  gap: var(--tc-space-2, 8px);
}

.dash-untergrund__haus {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  min-width: 0;
}

/* Seit dem 13.08.2026 ist jedes Haus ein Deep-Link in den Untergrund
   (untergrund.html?target=…). Die Flex-Zeile muss deshalb auf den Anker
   wandern — bliebe sie am <li>, waere der <a> ein Block darin und Icon und
   Text stuenden untereinander.
   min-height 44px ist die Touch-Vorgabe aus Leitplanke 10 des Briefings;
   auf dem Sofa wird diese Kachel mit dem Daumen bedient. */
/* Die angekuendigte Muenzschmelze auf dem Dashboard. Sie steht ueber dem
   rollierenden Ausruf, weil sie befristet ist und der Rest nicht — und weil
   das Dashboard der Ort ist, an dem die Leute landen (Briefing §7.2). */
.dash-untergrund__schmelze {
  margin: 0 0 var(--tc-space-3, 12px);
  padding: 10px 12px;
  border: 1px solid var(--tc-accent, #c9a959);
  border-left-width: 4px;
  border-radius: var(--tc-radius-md, 10px);
  background: rgba(var(--tc-accent-rgb, 201, 169, 89), 0.10);
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--tc-text-default, #b0b0b0);
}

.dash-untergrund__schmelze-marke {
  display: block;
  font-family: Cinzel, serif;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tc-highlight, #e8cf9a);
  margin-bottom: 3px;
}

/* Die letzten vierzehn Tage vor einer Schmelze werden waermer — dieselbe
   Schwelle wie beim Saisonband. Davor bleibt die Zeile ruhig: Eine Warnung,
   die hundert Tage lang schreit, hoert nach drei Tagen niemand mehr.
   (20.08.2026, als die wiederkehrende Saison-Schmelze diese Zeile uebernahm.) */
.dash-untergrund__schmelze.is-bald {
  border-color: #a4553c;
  background: rgba(164, 85, 60, 0.12);
}

.dash-untergrund__schmelze.is-bald .dash-untergrund__schmelze-marke { color: #d18a6a; }

.dash-untergrund__haus-link {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  min-width: 0;
  min-height: 48px;
  flex: 1;
  padding: 5px 8px;
  margin: 0 -8px;
  border-radius: var(--tc-radius-md, 8px);
  color: inherit;
  text-decoration: none;
  transition: background var(--tc-motion-normal, 200ms ease),
              transform var(--tc-motion-normal, 200ms ease);
}

.dash-untergrund__haus-link:hover,
.dash-untergrund__haus-link:focus-visible {
  background: rgba(var(--ug-bernstein-rgb), 0.14);
  transform: translateX(3px);
  outline: none;
}

.dash-untergrund__haus-link:focus-visible {
  box-shadow: 0 0 0 2px rgba(var(--ug-bernstein-rgb), 0.55);
}

/* Das Gesicht des Wirts. DAS ist der Zug der Kachel — fünf Emojis sind eine
   Liste, fünf Gesichter sind Leute, bei denen man vorbeischauen will.
   object-position oben, weil auf allen fünf Bildern das Gesicht im oberen
   Drittel sitzt. */
.dash-untergrund__haus-bild {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 22%;
  border: 1px solid rgba(var(--ug-bernstein-rgb), 0.55);
  box-shadow: 0 0 12px rgba(var(--ug-bernstein-rgb), 0.20);
  background: #14100c;
  transition: box-shadow var(--tc-motion-normal, 200ms ease),
              border-color var(--tc-motion-normal, 200ms ease);
}

.dash-untergrund__haus-link:hover .dash-untergrund__haus-bild {
  border-color: var(--ug-bernstein-hell);
  box-shadow: 0 0 18px rgba(var(--ug-bernstein-rgb), 0.45);
}

/* ⚠️ DER PFEIL STAND AUF `opacity: 0` — sichtbar wurde er erst beim Zeigen.
   Damit gab es im Ruhezustand KEINEN Hinweis darauf, dass die acht Haeuser
   Links sind, und Tim hat am 20.08.2026 gefragt, ob man sie klickbar machen
   koenne: „Und die hier sollten klickbar sein." Sie waren es seit dem
   13.08. — man sah es nur nicht. Am Handy gibt es ausserdem gar kein Hover,
   dort war der Hinweis also nie zu bekommen.
   Jetzt gedaempft sichtbar, beim Zeigen kraeftiger. */
.dash-untergrund__haus-pfeil {
  margin-left: auto;
  flex-shrink: 0;
  color: rgba(var(--ug-bernstein-rgb), 0.75);
  font-size: 0.95rem;
  opacity: 0.45;
  transform: translateX(0);
  transition: opacity var(--tc-motion-normal, 200ms ease),
              transform var(--tc-motion-normal, 200ms ease);
}

.dash-untergrund__haus-link:hover .dash-untergrund__haus-pfeil,
.dash-untergrund__haus-link:focus-visible .dash-untergrund__haus-pfeil {
  opacity: 1;
  transform: translateX(3px);
  color: var(--ug-bernstein-hell);
}

/* Am Handy gibt es kein Hover — dort steht der Pfeil dauerhaft, sonst sieht
   die Zeile aus, als führte sie nirgendwohin. */
@media (hover: none) {
  .dash-untergrund__haus-pfeil { opacity: 0.6; transform: none; }
}

/* ---------------------------------------------------------------------------
 * Der Rest der Kachel in der Untergrund-Palette.
 *
 * Diese Regeln stehen bewusst NACH den ursprünglichen: Sie überschreiben
 * dort, wo vorher --tc-highlight stand, also die Farbe des gerade aktiven
 * Systemthemes. Auf einem Blood-Bowl-Dashboard war die Kachel dadurch
 * gelb-grün, auf einem ToW-Dashboard teal — sie sah jedes Mal aus wie ein
 * Teil des Systems, statt wie der Ort, in den sie führt.
 * ------------------------------------------------------------------------- */
.dash-untergrund__titel { color: var(--ug-gold); font-size: 1.3rem; }
.dash-untergrund__titel a:hover { color: var(--ug-bernstein-hell); }

.dash-untergrund__marke {
  color: #17120c;
  background: var(--ug-bernstein);
  border-color: var(--ug-bernstein-hell);
}

.dash-untergrund__kasse {
  background: rgba(var(--ug-bernstein-rgb), 0.10);
  border-color: rgba(var(--ug-bernstein-rgb), 0.32);
}

.dash-untergrund__muenze {
  background: radial-gradient(circle at 30% 25%,
              rgba(var(--ug-bernstein-rgb), 0.45), rgba(0, 0, 0, 0.45));
  border-color: rgba(var(--ug-bernstein-rgb), 0.5);
}

.dash-untergrund__kasse-wert,
.dash-untergrund__kasse-wert .dash-teaser__num { color: var(--ug-gold); }

.dash-untergrund__ruf-wer   { color: var(--ug-bernstein-hell); }
.dash-untergrund__ruf-text  { color: #cdbb9a; }

.dash-untergrund__haus-name { color: #e6dcc8; }

/* Der Weg hinein — bewusst breit und in Bernstein. Er ist der einzige Knopf
   der Kachel und soll auch so aussehen; ein tc-button--primary hätte die
   Farbe des Systemthemes getragen. */
/* Der Weg hinein.
 *
 * Er war bis zum 13.08.2026 ein vollbreiter, satt gefüllter Balken — auf dem
 * Desktop wirkte er dadurch wie ein Formular-Absenden und zog mehr Aufmerksamkeit
 * als der Kontostand darüber. Jetzt ein Knopf in Knopfgröße: am Handy über die
 * volle Breite (dort ist das richtig, der Daumen braucht Fläche), ab 620px
 * mittig und nur so breit wie nötig. */
.dash-untergrund__fuss {
  margin-top: var(--tc-space-4, 16px);
  text-align: center;
}

.dash-untergrund__fuss .tc-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0 24px;
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #17120c;
  background: linear-gradient(180deg, var(--ug-bernstein-hell), var(--ug-bernstein));
  border: 1px solid rgba(var(--ug-bernstein-rgb), 0.9);
  box-shadow: 0 3px 14px rgba(var(--ug-bernstein-rgb), 0.22);
  transition: transform var(--tc-motion-normal, 200ms ease),
              box-shadow var(--tc-motion-normal, 200ms ease);
}

@media (min-width: 620px) {
  .dash-untergrund__fuss .tc-button { width: auto; min-width: 190px; }
}

.dash-untergrund__fuss .tc-button::after {
  content: '\2193';           /* Pfeil nach unten — man steigt hinab */
  font-size: 1.05em;
  line-height: 1;
}

.dash-untergrund__fuss .tc-button:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 22px rgba(var(--ug-bernstein-rgb), 0.38);
}

/* Die angekündigte Münzschmelze in derselben Palette */
.dash-untergrund__schmelze {
  border-color: var(--ug-bernstein);
  background: rgba(var(--ug-bernstein-rgb), 0.14);
  color: #cdbb9a;
}

.dash-untergrund__schmelze-marke { color: var(--ug-gold); }

/* ---------------------------------------------------------------------------
 * Zweispaltige Wirte ab 1000px — dort, wo Fortschritt und Untergrund
 * NEBENEINANDER stehen und das Ungleichgewicht entsteht (Tim, 13.08.2026):
 * Fünf Wirte untereinander machten die rechte Spalte mehr als doppelt so hoch
 * wie die linke.
 *
 * WARUM DIESER BLOCK GANZ AM ENDE STEHT: Er stand zuerst oben bei
 * `.dash-progress-split`, also VOR der Basisregel `.dash-untergrund__haeuser
 * { display: flex }`. Eine Media Query erhöht die Spezifität NICHT — die
 * spätere Regel hat gewonnen, `display` blieb `flex`, und im Browser sah
 * alles unverändert aus. Gemessen, nicht gelesen: gridTemplateColumns meldete
 * brav "1fr 1fr", während display "flex" war. Genau die Falle aus
 * CLAUDE.md §10.
 * ------------------------------------------------------------------------- */
@media (min-width: 1000px) {
  .dash-untergrund__haeuser {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px 18px;
  }
}

/* --- 3:3 statt 4:2 (Tim, 14.08.2026: „Kannst du die Dudes 3:3 anordnen?
 * Spart nochmal Platz.")
 *
 * WAS VORHER SCHIEFLIEF, und warum es niemand als Fehler gelesen hat: Die
 * Zweispalten-Regel stammt aus der Zeit mit FÜNF Wirten. Fünf auf zwei
 * Spalten sind zwei Reihen und ein Rest, und der Rest bekam mit
 * `:last-child { grid-column: 1 / -1 }` die volle Breite. Seit Old Krenk am
 * 14.08. das sechste Haus wurde, geht die Rechnung ohne Rest auf — die Regel
 * blieb aber stehen und zog den sechsten Wirt über beide Spalten. Ergebnis
 * war das 4:2-Bild mit einem Loch rechts unten. Merksatz: Eine Regel, die
 * eine ungerade Anzahl glattzieht, ist beim nächsten Eintrag falsch.
 *
 * Sechs teilt sich glatt durch drei — es braucht also gar keine
 * Sonderregel mehr, und sie ist ersatzlos gestrichen.
 *
 * Die Schwelle liegt bei 1100px und nicht schon bei 1000px: Darunter steht
 * die Kachel neben „Mein Fortschritt" und ist so schmal, dass drei Spalten
 * je rund 140px hätten — „Zum Gezinkten Würfel" bräuchte dort drei Zeilen.
 * Gemessen über sechs Kachelbreiten von 470 bis 760px, nicht geschätzt:
 * überall 3:3, nirgends etwas abgeschnitten, Zeilenhöhe 48px (breit) bis
 * 89px (sehr schmal).
 * ------------------------------------------------------------------------- */
@media (min-width: 1100px) {
  .dash-untergrund__haeuser {
    grid-template-columns: repeat(3, 1fr);
    gap: 4px 14px;
  }

  /* Bei drei Spalten wird der Platz je Wirt knapp. Der Pfeil ist reine
     Dekoration (der ganze Eintrag ist ohnehin ein Link) und weicht als
     Erstes — lieber ein lesbarer Name als ein Pfeil daneben. */
  .dash-untergrund__haeuser .dash-untergrund__haus-pfeil { display: none; }

  /* Und der Name darf umbrechen statt abzuschneiden. Gemessen: In der
     schmalen Kachel neben „Mein Fortschritt" braucht „Zum Gezinkten Würfel"
     mehr Platz, als drei Spalten unterhalb von 1440px hergeben — mit
     `nowrap` stand dort „Zum Gezinkten Wür…". Ein gekürzter Wirtsname ist
     schlechter als eine zweite Zeile, zumal das Raster alle Zeilen einer
     Reihe ohnehin auf gleiche Höhe zieht.
     Das Bild schrumpft dabei leicht mit — die 6px kommen dem Text zugute. */
  .dash-untergrund__haeuser .dash-untergrund__haus-name,
  .dash-untergrund__haeuser .dash-untergrund__haus-wirt {
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .dash-untergrund__haeuser .dash-untergrund__haus-bild {
    width: 34px;
    height: 34px;
  }
}


.dash-untergrund__haus-icon {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: var(--tc-radius-sm, 6px);
  display: grid;
  place-items: center;
  font-size: 0.85rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.07);
  /* Verschlossen — deshalb gedaempft, nicht voll ausgeleuchtet. */
  opacity: 0.75;
}

.dash-untergrund__haus-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.25;
}

.dash-untergrund__haus-name {
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--tc-text-default, #ddd);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-untergrund__haus-wirt {
  font-size: 0.72rem;
  font-style: italic;
  color: var(--tc-text-muted, #999);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Was man dort tut (20.08.2026). Die Kachel nannte bisher nur Ort und Person —
   dass hinter „Der Fehdestein" eine Kriegserklaerung steckt, musste man wissen
   oder hingehen. Leiser als der Wirt, damit die Zeile ordnet statt zu
   konkurrieren. */
.dash-untergrund__haus-tut {
  font-size: 0.68rem;
  line-height: 1.3;
  color: rgba(var(--ug-bernstein-rgb), 0.72);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 1px;
}

.dash-untergrund__haus-link:hover .dash-untergrund__haus-tut,
.dash-untergrund__haus-link:focus-visible .dash-untergrund__haus-tut {
  color: var(--ug-bernstein-hell);
}

/* ⚠️ HIER STAND EINE ZWEITE `.dash-untergrund__fuss`-REGEL (bis 20.08.2026).
   Ein Rest aus der Zeit, als der Fuss eine kleine graue Fussnote war —
   inzwischen steht der Hinabsteigen-Knopf darin, und der bringt Schrift und
   Farbe selbst mit. Wirksam war davon nur noch EINS, und das war schaedlich:
   die Kurzform `margin: 12px 0 0` hat das `margin-top: auto` aus der
   Streckungsregel zurueckgesetzt (CLAUDE.md §10, „Die Kurzform schlaegt die
   Langform"). Die Regel vom 16.08., die den Knopf nach unten schieben sollte,
   ist deshalb nie gelaufen. Aufgefallen ist es erst, als die linke Spalte
   doppelt so hoch wurde. */

/* ----------------------------------------------------------------------------
 * GETRAENKEKASSE IM ANMELDE-DIALOG
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: die Bitte sei "zu forsch". Der Text spricht jetzt als
 * Ausrufer (dashboard-events-extension.js, _kassenRuf) — das CSS haelt ihn
 * bewusst leise: kleiner, gedaempft, abgesetzt. Ein Spendenhinweis, der so
 * laut ist wie die Bestaetigung selbst, liest sich als Rechnung. ------------ */

.tc-join-kasse {
  margin: var(--tc-space-4, 16px) 0 0;
  padding-top: var(--tc-space-3, 12px);
  border-top: 1px solid var(--tc-border-subtle, rgba(255, 255, 255, 0.1));
  font-size: 0.84rem;
  line-height: 1.5;
}

.tc-join-kasse__wer {
  display: block;
  margin-bottom: 2px;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tc-highlight, #a1917a);
}

.tc-join-kasse__ruf {
  font-style: italic;
  color: var(--tc-text-muted, #999);
}

/* ----------------------------------------------------------------------------
 * DIE PUSH-FRAGE NACH DER ZUSAGE (#356, 22.08.2026)
 *
 * Steht ueber der Getraenkekasse und unter dem Kalender-Knopf — die drei
 * bilden zusammen die Antwort auf "was jetzt?". Sie ist WACHER gesetzt als die
 * Kassenzeile: Dort geht es um Geld und Zurueckhaltung ist geboten, hier um
 * eine Erinnerung, die der Leser sich gerade selbst wuenschen koennte.
 *
 * Kein eigener Knopf-Stil: `tc-button--secondary --sm` aus der Library (§3).
 * -------------------------------------------------------------------------- */

.tc-join-push {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--tc-space-2, 8px);
  margin: var(--tc-space-4, 16px) 0 0;
  padding: var(--tc-space-3, 12px);
  border: 1px solid var(--tc-border-subtle, rgba(255, 255, 255, 0.1));
  border-radius: var(--tc-radius-md, 8px);
  /* ⚠️ --tc-bg-subtle gibt es NICHT (§9: ein erfundener Tokenname faellt
     still aus, er wird nicht rot). Die Flaeche im Modal ist --tc-bg-surface-2,
     der Kasten darauf eine Stufe heller. */
  background: var(--tc-bg-surface-3, #3a3a3a);
}

.tc-join-push__frage {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--tc-text-strong, #e8e8e8);
}

.tc-join-push__hinweis {
  font-size: 0.8rem;
  /* ⚠️ NICHT --tc-text-muted. Nachgerechnet gegen die eigene Flaeche
     (--tc-bg-surface-3, #3a3a3a): 4,25:1 — unter den 4,5, die WCAG AA fuer
     Text dieser Groesse verlangt. Das Token ist gegen die HELLSTE vorkommende
     Flaeche geprueft, und die ist hier genau die, auf der es steht (§9). */
  color: var(--tc-text-default, #cdd9dd);
}

/* ============================================================================
 * TERMINE — neue Optik, unveraenderte Funktion
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Du kannst die Funktion gleich lassen. Aber die Optik
 * muss neu." Und vorher: "Das ist DAS wichtigste Feature der Plattform."
 *
 * Deshalb wird hier KEINE Zeile JavaScript angefasst. An den Terminen haengen
 * 2136 Zeilen mit 38 Funktionen — Kalender, Abwesenheiten mit Konfliktpruefung,
 * Match-Info fuer drei Systeme, BB-Fixtures, Sichtbarkeitsregeln. Diese
 * Sonderfaelle sind ueber Monate entstanden; beim Nachbauen verliert man
 * garantiert welche, und merken wuerde man es erst am Spielabend.
 *
 * Stattdessen bekommen die vorhandenen Klassen hier ein neues Aussehen. Das
 * greift nur auf der neuen Seite (nur sie laedt diese Datei), laesst jede
 * Funktion unberuehrt und ist jederzeit zurueckdrehbar.
 *
 * Formensprache wie der Rest der Seite: ruhige Flaechen, Systemfarbe als
 * schmale Kante statt als Rahmen, Tokens statt Festwerte.
 * ========================================================================== */

/* --- Rahmen: vom roten Kasten zur ruhigen Sektion ------------------------- */
.dash-page .events-section {
  background: transparent;
  border: none;
  border-radius: 0;
  margin: var(--tc-space-6, 24px) 0 0;
  overflow: visible;
}

/* Die Kopfzeile der Termine steht weiter unten im Abschnitt "TERMINE —
   Optik an die uebrigen Abschnitte angleichen". Hier stand bis zum
   12.08.2026 eine erste Fassung, die `h2 { flex: 1 1 100% }` setzte und
   damit die Knopfgruppe zwangsweise in eine zweite Zeile schob. Zwei
   Regelbloecke fuer dieselbe Zeile, der zweite konnte den ersten nicht
   vollstaendig ueberschreiben — deshalb blieb der Kalender-Knopf allein
   und zentriert unter der Ueberschrift stehen. */

.dash-page .events-list {
  padding: var(--tc-space-3, 12px) 0 0;
  gap: var(--tc-space-3, 12px);
}

/* --- Die Karte ----------------------------------------------------------- */
.dash-page .event-card {
  min-height: 0;                     /* 280px Mindesthoehe erzwang Leerraum */
  border: 1px solid rgba(255, 255, 255, 0.08);
  /* KORRIGIERT am 12.08.2026: Hier stand `var(--event-accent, …)`.
     Diese Variable hat im ganzen Repo NULL Schreiber — die echten heissen
     `--evt-color` / `--evt-accent` (css/dashboard.css:83-89, und inline
     gesetzt fuer Konfig-Termine in js/ui/dashboard-events.js). Die
     Systemfarbe an der linken Kante war damit seit dem Umbau tot: Jede
     Karte trug denselben Fallback-Ton, egal ob Mordheim oder Blood Bowl.
     Und Konfig-Termine mit eigener Farbe waren doppelt wirkungslos. */
  border-left: 3px solid var(--evt-color, var(--tc-accent, #a1917a));
  border-radius: var(--tc-radius-lg, 12px);
  background:
    linear-gradient(150deg,
      rgba(255, 255, 255, 0.035) 0%,
      rgba(255, 255, 255, 0.012) 55%,
      transparent 100%),
    var(--tc-bg-surface-1, #1f1f1f);
  transition:
    transform 200ms cubic-bezier(0.34, 1.3, 0.64, 1),
    border-color 200ms ease,
    box-shadow 200ms ease;
}

/* border-color als Kurzform wuerde die linke Systemfarb-Kante mit
   uebermalen — deshalb hier und beim naechsten Termin nur die drei
   uebrigen Seiten ansprechen. */
.dash-page .event-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
  border-top-color: rgba(255, 255, 255, 0.14);
  border-right-color: rgba(255, 255, 255, 0.14);
  border-bottom-color: rgba(255, 255, 255, 0.14);
}

/* Auf Touch gibt es kein Hover — der Browser laesst den Zustand nach dem
   Antippen stehen, und die Karte bleibt sichtbar angehoben zurueck.
   dashboard.css hat dafuer laengst einen Block ("Remove Hover Effects on
   Touch Devices"), der aber nur `transform` zuruecknimmt und ausserdem
   von diesen Regeln hier per Spezifitaet geschlagen wird (0,3,0 gegen
   0,2,0). Deshalb hier, vollstaendig, mit allen drei Eigenschaften —
   sonst kleben Schatten und heller Rahmen weiter. */
@media (hover: none) {
  .dash-page .event-card:hover {
    transform: none;
    box-shadow: none;
    border-top-color: rgba(255, 255, 255, 0.08);
    border-right-color: rgba(255, 255, 255, 0.08);
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }
}

/* Der naechste Termin darf sich abheben — er ist der einzige, der zaehlt,
   wenn man kurz aufs Handy schaut. */
.dash-page .event-card.is-next,
.dash-page .event-card.next-event {
  border-top-color: color-mix(in srgb, var(--tc-highlight, #d4c4a0) 40%, transparent);
  border-right-color: color-mix(in srgb, var(--tc-highlight, #d4c4a0) 40%, transparent);
  border-bottom-color: color-mix(in srgb, var(--tc-highlight, #d4c4a0) 40%, transparent);
  box-shadow: 0 0 0 1px rgba(212, 196, 160, 0.12), 0 8px 24px rgba(0, 0, 0, 0.4);
}

/* --- Datumsblock: vom blutroten Kasten zur ruhigen Kachel -----------------
 *
 * DURCHGESETZT am 12.08.2026 (Tim folgt der Empfehlung aus #270).
 * -------------------------------------------------------------------------
 * Die Absicht stand hier seit dem Umbau, kam aber nicht an: `dashboard.css:97`
 * faerbt `.event-card[data-event-type] .card-date-block` in der Systemfarbe
 * und gewinnt mit (0,2,0) gegen die (0,2,0) hier — bei Gleichstand entscheidet
 * die Ladereihenfolge, und dashboard.css kommt zuerst... aber der Selektor
 * dort ist durch das Attribut eine Klasse staerker. Deshalb greift hier
 * derselbe Attribut-Selektor.
 *
 * Warum das mehr als Geschmack ist: Auf der farbigen Kachel stand der
 * Wochentag mit --tc-text-muted (#888). Gemessen ergab das Community 1,24:1,
 * Old World 1,31:1, Blood Bowl 1,43:1, Pathfinder 1,85:1, AoS 2,36:1,
 * Mordheim 2,82:1 — durchweg unlesbar. Entweder Kachel neutral und Text
 * gedaempft, oder Kachel farbig und Text weiss. Die Mischform, die hier
 * entstanden war, ist in jedem Fall falsch.
 *
 * Entschieden: Kachel neutral. Die Systemfarbe traegt seit heute wieder die
 * linke Kante der Karte (sie war monatelang tot, siehe oben) und der Badge —
 * das reicht, um das System zu erkennen, ohne die wichtigste Zahl der Karte
 * auf einen farbigen Grund zu legen.
 * ------------------------------------------------------------------------- */
.dash-page .event-card .card-date-block,
.dash-page .event-card[data-event-type] .card-date-block {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--tc-radius-md, 8px);
  padding: 8px 10px;
  min-width: 56px;
}

/* Die Countdown-Zahl darf die Systemfarbe behalten — sie steht auf dem
   dunklen Kartengrund, nicht auf einer farbigen Flaeche, und ist damit das
   einzige farbige Element, das lesbar bleibt. Hier wird also NICHTS
   neutralisiert; der Hinweis steht nur da, damit niemand beim naechsten
   Durchgang aus Symmetriegruenden zugreift. */

.dash-page .date-day {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  color: var(--tc-highlight, #d4c4a0);
  font-variant-numeric: tabular-nums;
}

.dash-page .date-month,
.dash-page .date-weekday {
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tc-text-muted, #999);
}

/* --- Titel: darf umbrechen statt abzuschneiden --------------------------- */
.dash-page .card-title {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.02rem;
  line-height: 1.25;
  color: var(--tc-highlight, #d4c4a0);
  white-space: normal;               /* vorher: nowrap + ellipsis */
  overflow: visible;
  text-overflow: clip;
}

/* --- Zeilen ruhiger trennen ---------------------------------------------- */
.dash-page .card-row-info,
.dash-page .card-row-matches,
.dash-page .card-row-actions {
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.dash-page .card-countdown .countdown-value {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.3rem;
  color: var(--tc-highlight, #d4c4a0);
  font-variant-numeric: tabular-nums;
}

.dash-page .card-countdown .countdown-label {
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* 12.08.2026: war --tc-text-muted (#888) und kam auf 3,94:1 — unter
     AA. Uhrzeit, Ort und die Countdown-Beschriftung sind kein Beiwerk,
     sondern die Antwort auf "wann und wo"; die liest man im Vorbeigehen. */
  color: var(--tc-text-default, #b0b0b0);
}

/* Uhrzeit und Ort — derselbe Fall wie die Countdown-Beschriftung.
   css/dashboard.css:259 setzt `--text-muted` (#888888) auf der
   Kartenflaeche: gemessen 3,94:1, AA verlangt 4,5:1 fuer Fliesstext. */
.dash-page .card-meta {
  color: var(--tc-text-default, #b0b0b0);
}

/* --- Vergangene Termine --------------------------------------------------- */
.dash-page .past-events-section {
  margin-top: var(--tc-space-4, 16px);
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

.dash-page .past-events-header {
  padding: var(--tc-space-3, 12px) 0;
  min-height: var(--tc-touch-min, 36px);
  color: var(--tc-text-muted, #999);
  font-size: 0.85rem;
}

@media (prefers-reduced-motion: reduce) {
  .dash-page .event-card { transition: none; }
  .dash-page .event-card:hover { transform: none; }
}

/* ============================================================================
 * TOWN CRYER — angleichen, nicht einebnen
 * ----------------------------------------------------------------------------
 * Der Town Cryer ist die narrative Klammer der Plattform und laut Wissensbasis
 * §7 ein bewusst geschuetzter Solitaer ("die Town-Cryer-Eule als Identitaet").
 * Hier gilt die Anti-Bland-Klausel: Konsistenz heisst Struktur-Angleich, nicht
 * Verarmung. Gold, Cinzel und der warme Verlauf bleiben deshalb — er soll sich
 * abheben, das ist seine Aufgabe.
 *
 * Korrigiert wird nur, was mit der neuen Seite kollidiert.
 * ========================================================================== */

.dash-page .town-cryer-narrative-section {
  /* Der Block brachte einen eigenen Seitenabstand mit (--spacing-md). Zusammen
     mit dem Container-Padding der neuen Seite ergab das einen doppelten Rand:
     Der Town Cryer sass sichtbar weiter innen als alle anderen Bloecke. */
  margin: 0 0 var(--tc-space-5, 20px);
}

.dash-page .cryer-narrative {
  /* Linke Kante wie bei den System-Sektionen und Terminkarten, damit der Block
     in derselben Familie steht — die Fuellung bleibt seine eigene. */
  border-left: 3px solid var(--tc-highlight, #d4c4a0);
  border-radius: var(--tc-radius-lg, 12px);
}

/* ============================================================================
 * LIVE-BANNER
 * Es gibt tc-live-card (live-now.css), das Banner nutzt aber eigene
 * dashboard-live-*-Klassen. Statt das JS umzustellen — dieselbe Ueberlegung
 * wie bei den Terminen — bekommen die vorhandenen Klassen hier die Optik der
 * Komponente. Das Banner ist zeitkritisch und steht ganz oben; ein Fehler
 * darin faellt sofort auf.
 * ========================================================================== */

.dash-page #dashboard-live-banner:not(:empty) {
  margin-bottom: var(--tc-space-4, 16px);
}

.dash-page .dashboard-live-mine,
.dash-page .dashboard-live-other {
  border-radius: var(--tc-radius-lg, 12px);
  border-left: 3px solid var(--tc-danger, #c0392b);
}

.dash-page .dashboard-live-mine-title {
  font-family: var(--tc-font-display, 'Cinzel', serif);
  color: var(--tc-highlight, #d4c4a0);
}

/* Der Puls signalisiert "laeuft gerade" — die einzige dauerhafte Bewegung auf
   der Seite, und sie ist hier gerechtfertigt: Ein laufendes Match ist genau
   der Fall, fuer den "grosse Momente gross behandeln" gilt. */
.dash-page .dashboard-live-mine-icon {
  animation: dash-live-puls 2.2s ease-in-out infinite;
}

@keyframes dash-live-puls {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.72; transform: scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  .dash-page .dashboard-live-mine-icon { animation: none; }
}

/* ============================================================================
 * AUSRICHTUNG UND ABSTAENDE — Durchgang nach Tims Rueckmeldung (12.08.2026)
 * ----------------------------------------------------------------------------
 * "An die Ausrichtung und Abstaende musst du noch mal ran."
 *
 * Ursache war ein Flickenteppich: Jeder Block brachte seinen eigenen Abstand
 * mit (tc-hub__section aus der Library, .dash-section von mir, die
 * Termin-Sektion aus dashboard.css, der Town Cryer nochmal anders). Nebeneinander
 * ergab das ungleiche Luecken und Kanten, die nicht fluchten.
 *
 * Jetzt EIN Rhythmus fuer die ganze Seite:
 *   Abstand zwischen Bloecken   24px  (--tc-space-6)
 *   Innenabstand einer Sektion  16px  (--tc-space-4)
 *   Abstand innerhalb           12px  (--tc-space-3)
 * ========================================================================== */

/* Gleicher Abstand zwischen ALLEN Bloecken der Seite, egal woher sie kommen. */
.dash-page > * + * {
  margin-top: var(--tc-space-6, 24px);
}

/* Sektionen: gleiche Innenkante, damit Titel und Inhalt untereinander fluchten */
.dash-page .tc-hub__section {
  padding: var(--tc-space-4, 16px);
  margin: 0;
}

/* Die Sektionstitel sassen unterschiedlich weit oben — hier vereinheitlicht. */
.dash-page .tc-hub__section-title {
  margin: 0 0 var(--tc-space-3, 12px);
}

/* Raster innerhalb der Sektionen: ein Abstand statt drei verschiedener */
.dash-page .tc-statcard-grid,
.dash-page .dash-teaser-grid,
.dash-page .dash-rl-grid {
  gap: var(--tc-space-3, 12px);
}

/* ----------------------------------------------------------------------------
 * WERKBANK UND RANGLISTEN NEBENEINANDER (Tim, 14.08.2026)
 * ----------------------------------------------------------------------------
 * "Das ist aktuell beides zu raumfordernd. Ggf dann auch andere etwas
 * kompaktere Komponenten nutzen. Das sieht aktuell beides sehr funktional
 * aus, aber noch nicht so engaging."
 *
 * Das Nebeneinander bringt `.dash-split` mit (ab 1000px zwei Spalten) — das
 * vorhandene Raster, kein neues. Hier steht nur, was in der halben Spalte
 * anders sein muss:
 *
 * 1. Die drei Ranglisten bleiben NEBENEINANDER, auch in der halben Spalte.
 *    Das ist der ganze Gewinn: gemessen 299px statt 661px. Untereinander
 *    gestapelt wäre die Rangliste höher geworden als beide Blöcke vorher
 *    zusammen — die Kachel wäre schmaler, die Seite aber nicht kürzer.
 *    Die Basisregel `minmax(240px, 1fr)` ergäbe in 688px nur zwei Spalten
 *    plus eine allein darunter (dieselbe ausgefranste Reihe wie bei den
 *    sechs Wirten). 140px statt 240px als Untergrenze, weil die Zeilen hier
 *    kompakter sind — gemessen passen drei Spalten damit schon ab 1000px
 *    (148px je Spalte, nichts abgeschnitten). `auto-fit` statt fester
 *    Dreizahl, damit es auf schmaleren Kacheln von selbst zurückfällt statt
 *    Namen abzuschneiden; die überzählige Spur kollabiert nachweislich auf
 *    0px, es klafft also keine Lücke rechts.
 * 2. Kompaktere Zeilen. Aus fünf Einträgen je Liste sind drei geworden
 *    (dashboard-teaser.js), und die Wert-Einheit je Zeile ist weg — sie war
 *    der eigentliche Höhentreiber (51px Zeilenhöhe statt 32px).
 * 3. Der eigene Platz hängt unter dem Treppchen, abgesetzt durch eine
 *    gestrichelte Linie — sichtbar als "gehört dazu, ist aber nicht Rang 4".
 * ------------------------------------------------------------------------- */
/* ⚠️ DIE DREISPALTIGKEIT IST AM 16.08.2026 ENTFALLEN. Der Kasten darueber
   beschreibt den Stand vom 14.08. und bleibt als Begruendung stehen — die
   Rechnung darin (299px statt 661px) war richtig, die Schlussfolgerung hat
   sich nur ueberholt.
   Tim: "Sie sieht nicht sonderlich ansprechend aus und ich fuerchte, dass sie
   auch nicht wahnsinnig aktivierend ist. […] nutze dann library komponenten
   um die optisch aufzuwerten."
   Drei Listen in der halben Spalte hiessen 148px je Liste. Darin passt kein
   Podium, keine Medaille und kein langer Name — es MUSSTE eine karge Tabelle
   bleiben.

   ⚠️ UND AUCH DER UMSCHALTER IST WIEDER WEG (16.08.2026, Taskwerk #330).
   Fassung 2 legte zwei der drei Wertungen hinter `tc-tabs`. Tim: "Man klickt
   hier keine unterschiedlichen Systeme an. Das hat man in den Hubs. Hier muss
   aggregierte Info rein." Auf einer Uebersicht zwei Drittel des Inhalts hinter
   einen Reiter zu legen, verfehlt den Zweck der Seite.
   Der Abschnitt heisst jetzt `.dash-fk` (Faktensammlung) — die 26 Regeln der
   Fassungen 1 und 2 sind entfernt, weil ihr Markup nicht mehr entsteht.
   `.dash-rl-grid` bleibt: Die Klasse steht als Container im Markup von
   dashboard.html und wird von renderRanglisten() befuellt. */

/* Beide Hälften beginnen oben, statt sich auf gleiche Höhe zu strecken —
   die Werkbank ist mal kürzer, mal länger als die Ranglisten. */
.dash-split--werkbank { align-items: start; }

/* Gestapelt (unter 1000px) darf die Werkbank ihren eigenen Abstand behalten;
   sonst kleben ihre CTAs an der Ranglisten-Überschrift. */
@media (max-width: 999px) {
  .dash-split--werkbank > * + * { margin-top: var(--tc-space-4, 16px); }
}

/* Die Statcards standen unterschiedlich hoch, wenn eine zwei Zeilen Label
   hatte. Gleiche Mindesthoehe laesst die Reihe fluchten. */
.dash-page .tc-statcard {
  min-height: 72px;
  align-items: center;
}


/* Die Sektionskoepfe (Meine Spiele / Ranglisten) hatten mehr Luft nach unten
   als die Bloecke darunter — das liess sie schweben. */
.dash-page .dash-section__head {
  margin-bottom: var(--tc-space-3, 12px);
}

.dash-page .dash-section {
  margin-top: var(--tc-space-6, 24px);
}

/* Auf dem Handy schrumpft der Rhythmus mit — 24px zwischen jedem Block sind
   dort ein Drittel des sichtbaren Bereichs. */
@media (max-width: 600px) {
  .dash-page > * + * { margin-top: var(--tc-space-4, 16px); }
  .dash-page .dash-section { margin-top: var(--tc-space-4, 16px); }
  .dash-page .tc-hub__section { padding: var(--tc-space-3, 12px); }
  .dash-page .tc-statcard { min-height: 64px; }
}

/* ============================================================================
 * DICHTE — gemessen, nicht geschaetzt (12.08.2026)
 * ----------------------------------------------------------------------------
 * Nachgemessen auf 375x812: Die Seite war 4324px lang, also 5,3 Bildschirme.
 * Und schwerwiegender: Push-Banner + Town Cryer + Fortschritt ergaben 886px,
 * bevor die Termine begannen — Tims wichtigstes Feature lag damit vollstaendig
 * unter der Falzlinie.
 *
 * Groesster Einzelposten war der Statcard-Block: Bei genau drei Kennzahlen
 * belegten sie zwei Zeilen, die zweite nur halb gefuellt. 178px fuer drei
 * Zahlen, viermal auf der Seite.
 *
 * Loesung: Bei drei Kacheln alle drei nebeneinander, dafuer kompakter. Das
 * spart rund 90px je Sektion, ohne eine einzige Information zu streichen.
 * ========================================================================== */

@media (max-width: 600px) {
  /* Genau drei Kacheln: eine Zeile statt zwei. :has() waere eleganter, ist
     aber noch nicht ueberall verlaesslich — deshalb ueber die Kinderzahl. */
  .dash-page .tc-statcard-grid {
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  }

  /* Kompakter, damit drei nebeneinander lesbar bleiben */
  .dash-page .tc-statcard {
    min-height: 0;
    padding: 9px 8px;
    gap: 6px;
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }

  .dash-page .tc-statcard__icon {
    font-size: 0.95rem;
    width: auto;
    height: auto;
    min-width: 0;
    background: none;
    border: none;
    padding: 0;
  }

  .dash-page .tc-statcard__value {
    font-size: 1.25rem;
    line-height: 1.1;
  }

  .dash-page .tc-statcard__label {
    font-size: 0.62rem;
    letter-spacing: 0.04em;
    line-height: 1.2;
    /* Nur an Wortgrenzen umbrechen. `anywhere` zerriss "Schattengold" zu
       "SCHATTENGOL / D" — im Screenshot sofort als Fehler zu erkennen.
       (Die Kurzformen, auf die hier verwiesen wurde, gab es fuer die
       System-Kacheln; die sind am 13.08.2026 zu Zeilen geworden und
       brauchen keine mehr. Diese Regel gilt weiter fuer die uebrigen
       tc-statcard der Seite: Fortschritt und Untergrund.) */
    overflow-wrap: break-word;
    hyphens: auto;
  }

  /* Namen und Titel brauchen die volle Breite — sie in ein Drittel zu
     zwaengen macht sie unlesbar. Welche Werte das sind, entscheidet das JS
     ueber `is-breit`; hier stand vorher `:has(.is-text)`, und das traf
     auch die Bilanz "6–0–0" (is-text heisst nur "nicht hochzaehlen").
     Die Karten dahinter rutschten dadurch je allein in ihre Zeile.
     ------------------------------------------------------------------
     Der Zwilling dieser Regel fuer .dash-sys ist am 13.08.2026 mit der
     System-Kachel weggefallen; hier gilt sie weiter fuer die uebrigen
     tc-statcard-Vorkommen der Seite (Fortschritt, Untergrund). */
  .dash-page .tc-statcard.is-breit {
    grid-column: 1 / -1;
  }

  /* Der Rang darf schrumpfen, er steht ohnehin gross da */
  .dash-page .dash-fortschritt__rang-icon { font-size: 1.6rem; }
  .dash-page .dash-fortschritt__rang-name { font-size: 1.1rem; }
  .dash-page .dash-fortschritt__rang { margin-bottom: var(--tc-space-3, 12px); }
}

/* ============================================================================
 * TASTATURBEDIENUNG
 * ----------------------------------------------------------------------------
 * Nachgemessen: Kein interaktives Element der Seite hatte einen sichtbaren
 * Fokus-Ring, ueberall stand `outline: none`. Wer mit der Tastatur navigiert,
 * sieht damit nicht, wo er gerade ist — und tippt blind.
 *
 * `:focus-visible` statt `:focus`: Der Ring erscheint bei Tastaturbedienung,
 * nicht beim Antippen mit dem Finger oder Klicken mit der Maus. Genau das
 * Verhalten, das man will — sichtbare Hilfe fuer die, die sie brauchen, kein
 * Rahmen um jeden angetippten Knopf.
 * ========================================================================== */

.dash-page a:focus-visible,
.dash-page button:focus-visible,
.dash-page [tabindex]:focus-visible {
  outline: 2px solid var(--tc-highlight, #d4c4a0);
  outline-offset: 2px;
  border-radius: var(--tc-radius-sm, 6px);
}

/* Ganze Kacheln bekommen den Ring aussen herum statt am Text */

/* Terminkarten und Kalenderzeilen sind seit dem 12.08.2026 anfahrbar (#269).
 * Die Regel steht bewusst OHNE `.dash-page` davor: Die Zeilen der
 * Terminuebersicht entstehen im Modal, und das haengt nicht unter dem
 * Seitencontainer — mit Vorfahren-Selektor waere der Ring dort unsichtbar
 * geblieben, genau da, wo die lange Liste liegt. */
.event-card:focus-visible,
.all-events-row:focus-visible {
  outline: 2px solid var(--tc-highlight, #d4c4a0);
  outline-offset: 3px;
  border-radius: var(--tc-radius-md, 10px);
}

/* ============================================================================
 * LAYOUT-STABILITAET
 * ----------------------------------------------------------------------------
 * Die Bloecke werden per JS gefuellt und waren vorher 0px hoch. Beim Laden
 * sprang die Seite deshalb sichtbar: Man begann zu lesen, und der Text
 * rutschte unter dem Finger weg.
 *
 * `:empty` greift nur, solange der Container leer ist — sobald der Inhalt
 * steht, bestimmt der die Hoehe. Kein Leerraum bei wenig Inhalt.
 * ========================================================================== */

.dash-page #dashProgress:empty {
  min-height: 300px;
}

.dash-page #dashRanglisten:empty {
  min-height: 240px;
}

/* Der Platzhalter fuer die Systemkacheln stand schon, bekommt aber dieselbe
   Hoehe wie eine echte Sektion, damit der Tausch nicht springt. */
.dash-page .dash-teaser-skeleton {
  min-height: 200px;
}

@media (max-width: 600px) {
  .dash-page #dashProgress:empty { min-height: 260px; }
  .dash-page #dashRanglisten:empty { min-height: 200px; }
  .dash-page .dash-teaser-skeleton { min-height: 170px; }
}

/* ============================================================================
 * SEITENKOPF — alte Buehne weg, Konvention rein
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Das Seitenintro (Buehne) entspricht nicht unseren
 * Konventionen." Und: "Der Spenden Button kann wo anders hin."
 *
 * PageLayout.renderHeader() baut die Pergament-Buehne samt Gruss-Zeile. Das
 * ist geteilter Code und darf fuer die anderen Seiten nicht angefasst werden —
 * hier wird er deshalb nur ausgeblendet und durch den tc-page-header aus dem
 * Markup ersetzt. Gespart: rund 400px, bevor der erste Inhalt kommt.
 * ========================================================================== */

.dash-page-body #page-header {
  display: none;
}

/* Der Kopf sitzt am Seitenanfang buendig, ohne den Container-Rand — ein
   Banner, das eingerueckt ist, sieht aus wie eine Karte, nicht wie ein Kopf. */
.dash-page .tc-page-header {
  margin: 0 0 var(--tc-space-5, 20px);
}

/* ============================================================================
 * SPENDEN IM FUSS
 * Der Knopf stand im Kopfbereich und hatte dort eine eigene Zeile. Er ist ein
 * freundliches Angebot, kein Einstiegspunkt — im Fuss steht er richtig.
 * ========================================================================== */

.dashboard-footer .paypal-getraenkekasse-btn {
  margin: var(--tc-space-3, 12px) auto 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tc-touch-min, 36px);
}

/* ============================================================================
 * TOWN CRYER — Feed statt Karussell
 * ----------------------------------------------------------------------------
 * Die Meldungen selbst tragen tc-newsfeed/tc-news-item aus der Library. Hier
 * steht nur, was den Bereich in die Seite einpasst: der Ausruf ueber dem Feed
 * und der Knopf, der wie die uebrigen "mehr"-Links aussieht (er ist ein
 * <button>, weil er nachlaedt statt zu verlinken — Optik gleich, Semantik
 * richtig).
 * ========================================================================== */

/* Das Archiv des Ausrufers steht seit dem 12.08.2026 IN der Buehne (Tim:
   "muss oben in die Buehne an den TownCryer"). Sein CSS liegt deshalb weiter
   unten bei den uebrigen Buehnen-Regeln, unter .dash-buehne__archiv. */

/* ============================================================================
 * DIE BUEHNE — Begruessung + Ausrufer in einem
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Kannst du nicht eine Buehnenvariante bauen, die die
 * Begruessung und den TownCryer enthaelt? Ueber langsam rollierende Texte?
 * Dann koennte ich den TownCryer selbst als Person in das Headerbild bauen."
 *
 * Aufgebaut auf tc-page-header--banner, nicht daneben: Groesse, Bild-Layer,
 * Titel und Untertitel kommen unveraendert aus der Library. Hier steht nur,
 * was diese eine Seite ergaenzt — der Ausruf und der Platz fuer die Figur.
 * ========================================================================== */

.dash-buehne {
  --tc-header-banner-h: 340px;
  position: relative;
  overflow: hidden;
}

.dash-buehne__inhalt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 100%;
  max-width: 640px;
  text-align: center;
}

/* --- Platz fuer die gezeichnete Figur -----------------------------------
 * Greift NUR mit geladenem Banner (Klasse kommt aus _bannerPruefen()).
 * Ohne Bild bleibt die Buehne mittig — sonst staende der Text an der Seite
 * und daneben nichts, was wie ein Fehler aussieht.
 *
 * BILDVORGABE, damit Text und Figur sich nicht ins Gehege kommen:
 *   Desktop  ab 901px : Figur in der LINKEN Bildhaelfte (etwa 0–38 %)
 *   Handy   bis 900px : Figur OBEN (etwa obere 40 %), Text darunter
 * Der Rest der Flaeche darf ruhig Kulisse sein — der Text liegt auf einem
 * Verlauf und bleibt auch ueber Details lesbar.
 * -------------------------------------------------------------------- */

.dash-buehne.has-banner .dash-buehne__inhalt {
  align-items: flex-start;
  text-align: left;
}

/* ANGEPASST am 12.08.2026, als das Bild da war.
   ---------------------------------------------------------------------------
   Geplant war eine Figur LINKS, und die Regeln raeumten entsprechend die
   linken 38 % frei. Tims Ausrufer steht aber MITTIG im Bild — der Text lag
   damit quer ueber seinem Gesicht.
   Jetzt das klassische Hero-Muster: Bild oben, Text unten, Verlauf
   dazwischen. Das funktioniert unabhaengig davon, wo im Bild die Figur
   steht, und macht die Buehne unempfindlich gegen einen spaeteren
   Bildtausch. */

.dash-buehne.has-banner {
  justify-content: flex-end;
  padding-top: 190px;
}

/* Der Ausschnitt sitzt im oberen Bilddrittel: Dort ist das Gesicht.
   Bei `center center` (Vorgabe aus header.css) schneidet der flache
   Kopfbereich dem Ausrufer die Stirn ab. */
.dash-buehne.has-banner .tc-page-header__banner-img {
  object-position: center 22%;
  opacity: 0.62;
}

/* Der Verlauf traegt den Text. Zwei Halte statt einem: oben lange nichts,
   damit das Bild wirkt, dann zuegig dunkel. Ein linearer Verlauf ueber die
   ganze Hoehe legt schon oben einen Grauschleier ueber das Motiv. */
.dash-buehne.has-banner::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 72%;
  background: linear-gradient(180deg,
              rgba(0, 0, 0, 0) 0%,
              rgba(0, 0, 0, 0.55) 45%,
              rgba(0, 0, 0, 0.88) 100%);
  z-index: 0;
  pointer-events: none;
}

@media (min-width: 901px) {
  /* Am Schreibtisch ist der Kopf flacher (mehr Breite, gleiche Hoehe) —
     der Ausschnitt zeigt dort ohnehin nur einen Streifen. Etwas mehr
     Hoehe gibt der Figur Luft. */
  .dash-buehne.has-banner {
    --tc-header-banner-h: 420px;
    padding-top: 210px;
  }
}

/* --- Der Ausruf ---------------------------------------------------------- */

.dash-buehne__ruf {
  margin-top: var(--tc-space-3, 12px);
  width: 100%;
}

.dash-buehne__ruf-intro {
  margin: 0 0 4px;
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tc-highlight, #c9a959);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
}

/* min-height haelt die Buehne ruhig: Ohne sie springt die ganze Seite bei
   jedem Wechsel, weil kurze und lange Meldungen unterschiedlich hoch sind. */
.dash-buehne__ruf-text {
  margin: 0;
  min-height: 4.6em;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--tc-text-default, #ddd);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.85);
  opacity: 1;
  transition: opacity 200ms var(--tc-ease-out, ease);
}

.dash-buehne__ruf-text.ist-wechselnd { opacity: 0; }
.dash-buehne__ruf-text strong { color: var(--tc-highlight, #d4c4a0); }
.dash-buehne__ruf-text em { color: var(--tc-text-muted, #aaa); }

/* "Ganzen Bericht lesen" — der Weg aus der Buehne in den langen Bericht
   (13.08.2026). Er erscheint nur bei Meldungen, die einen tragen, und
   springt im Archiv genau auf diese eine. Ohne ihn lagen die
   Schlachtberichte zwei Aufklapper tief und wurden praktisch nie gelesen.
   Bewusst ein flacher Textknopf: Ein gefuellter Knopf neben dem Ausruf
   waere lauter als der Ausruf selbst. */
.dash-buehne__ruf-mehr {
  align-self: flex-start;
  margin-top: var(--tc-space-1, 4px);
  padding: 0;
  /* Touch-Ziel ohne sichtbare Flaeche (Leitplanke 10): Der Knopf sitzt
     zwischen Ausruf und Blaetterpfeilen, ein Fehlgriff waere aergerlich. */
  min-height: 44px;
  background: none;
  border: 0;
  font-family: var(--tc-font-body, inherit);
  font-size: var(--tc-text-xs, 0.8rem);
  font-weight: var(--tc-weight-semibold, 600);
  color: var(--tc-highlight, #d4c4a0);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.85);
  cursor: pointer;
  transition: color var(--tc-motion-fast) var(--tc-ease-out);
}
.dash-buehne__ruf-mehr[hidden] { display: none; }
.dash-buehne__ruf-mehr:hover { text-decoration: underline; }
.dash-buehne__ruf-mehr:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--tc-accent-glow, rgba(212, 196, 160, 0.4));
  border-radius: var(--tc-radius-sm, 4px);
}

/* --- Blaettern ----------------------------------------------------------- */

.dash-buehne__nav {
  display: inline-flex;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  margin-top: var(--tc-space-2, 8px);
  align-self: center;
}

/* --- Alle Neuigkeiten: das Archiv des Ausrufers, in der Buehne ----------
 *
 * Umgezogen am 12.08.2026 (Tim: "muss oben in die Buehne an den TownCryer,
 * das scheint da ein Ueberbleibsel zu sein"). Vorher stand es als eigene
 * Sektion 400 Pixel weiter unten, mit eigenem Rahmen und ohne sichtbaren
 * Bezug zu dem Ausrufer, dessen Meldungen es sammelt.
 *
 * Die Gestaltung ist hier bewusst zurueckhaltender als in der alten
 * Sektion: In der Buehne liegt der Block auf einem Bild und darf es nicht
 * zerschneiden. Deshalb kein voller Rahmen, sondern nur eine Trennlinie
 * nach oben — der Aufklapper wirkt als Fussnote des Ausrufs, nicht als
 * zweiter Kasten. --------------------------------------------------- */

/* ============================================================================
 * HIER STANDEN DIE REGELN DES AUFKLAPPERS "ALLE NEUIGKEITEN" (bis 13.08.2026)
 * ----------------------------------------------------------------------------
 * Entfernt, weil der Block kein <details> in der Buehne mehr ist, sondern ein
 * offener Abschnitt hinter den Terminen (dashboard.html, Abschnitt 2). Er
 * benutzt jetzt .dash-section wie die uebrigen Abschnitte der Seite.
 *
 * Weg sind damit: __archiv (Rahmen oben), __archiv-kopf (die Summary-Zeile mit
 * dem drehenden Pfeil), __archiv-titel, __archiv-zahl (die Pille mit der
 * Anzahl) und die Sonderbehandlung des Feeds, der auf dem Bannerbild einen
 * dunklen Grund und eine Hoehenbegrenzung brauchte. Im Seitenfluss braucht er
 * beides nicht mehr — und die Begrenzung auf 46vh war ohnehin der Grund, warum
 * man im Archiv scrollen musste statt zu lesen.
 *
 * Geblieben ist nur der Knopf darunter. Sein Name traegt noch das alte
 * Praefix; umbenannt wird er beim naechsten Anfassen, ein Rename allein waere
 * Bewegung ohne Wirkung.
 * ========================================================================== */

.dash-buehne__archiv-mehr {
  display: block;
  width: 100%;
  margin-top: var(--tc-space-2, 8px);
  padding: 8px;
  min-height: var(--tc-touch-min, 36px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--tc-radius-md, 8px);
  background: rgba(0, 0, 0, 0.4);
  color: var(--tc-text-muted, #999);
  font-family: inherit;
  font-size: 0.8rem;
  cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease;
}

.dash-buehne__archiv-mehr:hover,
.dash-buehne__archiv-mehr:focus-visible {
  color: var(--tc-highlight, #d4c4a0);
  border-color: rgba(255, 255, 255, 0.2);
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  .dash-buehne__archiv-kopf::after { transition: none; }
}

/* Mit Banner steht der Text linksbuendig — dann gehoert die Blaetterzeile
   auch nach links und nicht unter die Mitte des Absatzes. */
.dash-buehne.has-banner .dash-buehne__nav { align-self: flex-start; }

.dash-buehne__pfeil {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tc-touch-min, 36px);
  height: var(--tc-touch-min, 36px);
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.35);
  color: var(--tc-text-muted, #aaa);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease, background 160ms ease;
}

.dash-buehne__pfeil:hover,
.dash-buehne__pfeil:focus-visible {
  color: var(--tc-highlight, #d4c4a0);
  border-color: var(--tc-accent, #c9a959);
  background: rgba(0, 0, 0, 0.55);
  outline: none;
}

.dash-buehne__punkte {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Zaehler-Variante ab 7 Meldungen — siehe _rufStarten(). */
.dash-buehne__punkte.ist-zaehler {
  min-width: 62px;
  justify-content: center;
}

.dash-buehne__zaehler {
  font-family: var(--tc-font-body);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--tc-text-muted, #999);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
}

/* Der Punkt ist klein, seine Trefferflaeche nicht: 8px sichtbar in einem
   28px-Feld (Heuristik 5 — am Handy trifft man sonst daneben). */
.dash-buehne__punkt {
  position: relative;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.dash-buehne__punkt::before {
  content: '';
  position: absolute;
  inset: 50% auto auto 50%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
  transition: background 180ms ease, transform 180ms ease;
}

.dash-buehne__punkt.ist-aktiv::before {
  background: var(--tc-accent, #c9a959);
  transform: scale(1.35);
}

.dash-buehne__punkt:focus-visible::before {
  box-shadow: 0 0 0 2px var(--tc-highlight, #d4c4a0);
}

@media (prefers-reduced-motion: reduce) {
  .dash-buehne__ruf-text { transition: none; }
  .dash-buehne__ruf-text.ist-wechselnd { opacity: 1; }
  .dash-buehne__punkt::before { transition: none; }
}

/* Der Feed erbt die Library-Optik; nur die Fliesstext-Groesse hebe ich an.
   tc-text-sm ist fuer Log-Zeilen gedacht — hier sind es ganze Saetze, die
   gelesen werden wollen. */
.dash-page .tc-news-item__text {
  font-size: 0.9rem;
  line-height: 1.55;
}

.dash-page .tc-news-item__icon {
  font-size: 1.25rem;
}

/* ============================================================================
 * TERMINE — Optik an die uebrigen Abschnitte angleichen
 * ----------------------------------------------------------------------------
 * Tim: "Das ist DAS wichtigste Feature der Plattform" und "Bei den Terminen
 * gibts vielleicht bessere Lösungen."
 *
 * Nicht angefasst wird die Funktion: renderAllEvents() und renderEventCard()
 * (411 Zeilen, jede Menge Zustaende) bleiben Zeile fuer Zeile, wie sie sind.
 * Geaendert wird die Hierarchie — und die ist hier das eigentliche Problem:
 * drei gleich grosse Karten beantworten die Frage "was kommt als Naechstes?"
 * genauso laut wie "was kommt in drei Wochen?".
 *
 * Deshalb: Der naechste Termin bleibt in voller Groesse, die dahinter werden
 * kompakt. Das spart rund 300px und macht die Reihenfolge lesbar.
 * ========================================================================== */

/* Kopfzeile wie dash-section__head — Titel links, Aktionen rechts.
   Alle vier Eigenschaften stehen ausgeschrieben, obwohl dashboard.css
   schon flex setzt: Diese Zeile hat mich zweimal gekostet, weil dort
   ausserdem ein roter Verlauf und 20px/25px Innenabstand liegen. Wer sie
   nur teilweise ueberschreibt, bekommt eine Kopfzeile, die anders
   aussieht als jede andere auf der Seite.

   justify-content bewusst flex-start statt space-between: Bei
   space-between und umgebrochener Zeile sass der Titel mittig statt
   links. Die Knopfgruppe holt sich ihre rechte Kante ueber
   margin-left:auto — das haelt in beiden Faellen. */
.dash-page .events-header {
  display: flex;
  /* flex-direction ausdruecklich: dashboard.css stellt unter 480px auf
     `column` + `text-align: center` um. Genau das liess Titel und Knoepfe
     mittig untereinander stehen — und weil `column` nur in einem Media
     Query steht, war davon in der Regel darueber nichts zu sehen. */
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: var(--tc-space-2, 8px);
  margin: 0 0 var(--tc-space-3, 12px);
  padding: 0 0 var(--tc-space-2, 8px);
  background: none;
  border: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 0;
  text-align: left;
}

.dash-page .events-header h2 {
  margin: 0;
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--tc-highlight, #d4c4a0);
  text-align: left;
}

/* Die Knopf-Gruppe rechts: kleiner, ruhiger, gleiche Hoehe.
   margin-left:auto haelt sie auch dann rechts, wenn sie umbricht — bei
   space-between allein wuerde die einzeln stehende Zeile linksbuendig
   herausfallen. */
.dash-page .events-header > div {
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-left: auto;
  gap: var(--tc-space-2, 8px) !important;
}

.dash-page .events-header .btn-new-event {
  min-height: var(--tc-touch-min, 36px);
  padding: 6px 12px !important;
  font-size: 0.78rem !important;
  border-radius: var(--tc-radius-md, 8px);
  /* ERGAENZT am 12.08.2026: `width` fehlte hier — und genau das setzt
     css/dashboard.css unter 480px auf 100%. Die zwei Verwaltungsknoepfe
     (Kalender, Termin verkuenden) standen deshalb am Handy als
     vollbreite Bloecke uebereinander und kosteten rund 75px im Kopf des
     wichtigsten Blocks der Seite. Klassischer Fall aus TECHNISCHE-
     PATTERNS "CSS-Konflikte": Wer nur die stoerenden Eigenschaften
     ueberschreibt, uebersieht die eine, die er nicht genannt hat. */
  width: auto;
}

/* --- Hierarchie: Folgetermine kompakter als der naechste ---------------- */

/* Der naechste Termin behaelt alles. Die dahinter geben Paddings ab ... */
.dash-page .event-card:not(.next-event):not(.event-card-more) .card-row-top,
.dash-page .event-card:not(.next-event):not(.event-card-more) .card-row-info,
.dash-page .event-card:not(.next-event):not(.event-card-more) .card-row-matches,
.dash-page .event-card:not(.next-event):not(.event-card-more) .card-row-actions {
  padding-top: var(--tc-space-2, 8px);
  padding-bottom: var(--tc-space-2, 8px);
}

/* ... und ihr Aufruf-Knopf wird zur Zeile statt zur Flaeche. Die Zusage
   bleibt an Ort und Stelle klickbar — sie wird nur nicht mehr angeschrien. */
.dash-page .event-card:not(.next-event) .card-row-actions .btn-cta {
  width: auto;
  min-height: var(--tc-touch-min, 36px);
  padding: 8px 16px;
  font-size: 0.85rem;
}

/* Der Teilnehmen-Knopf war btn-primary — also Oxblood. Rot heisst auf dieser
   Plattform sonst "Achtung" (Gefallene, Absagen, Loeschen). Eine Zusage ist
   das Gegenteil davon. Auf dem Dashboard traegt sie deshalb den Akzent des
   aktiven Themes. Nur hier — .btn-primary bleibt plattformweit, wie es ist.

   Der Verlauf mischt bewusst mit WEISS und nicht mit `transparent`:
   color-mix(... , transparent) senkt den Alphawert, der Knopf wird
   milchig statt heller. */
.dash-page .event-card .card-row-actions .btn-cta.btn-primary {
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--tc-accent, #c9a959) 82%, #fff),
              var(--tc-accent, #c9a959));
  border-color: color-mix(in srgb, var(--tc-accent, #c9a959) 70%, #000);
  color: #1a1208;
  font-weight: 600;
  text-shadow: none;
}

.dash-page .event-card .card-row-actions .btn-cta.btn-primary:hover,
.dash-page .event-card .card-row-actions .btn-cta.btn-primary:focus-visible {
  background: var(--tc-highlight, #d4c4a0);
  border-color: var(--tc-highlight, #d4c4a0);
}

/* Die CTA-Zeile darunter ("Freie Plätze suchen" / "Termin bei Tim anfragen")
   kommt mit Inline-Styles aus dem JS. Ueberschreiben statt anfassen. */
.dash-page .no-slot-cta button {
  min-height: var(--tc-touch-min, 36px);
  border-radius: var(--tc-radius-md, 8px) !important;
  border-color: var(--tc-border-subtle, rgba(201, 169, 89, 0.2)) !important;
  color: var(--tc-text-muted, #999) !important;
  transition: color 160ms ease, border-color 160ms ease;
}

.dash-page .no-slot-cta button:hover,
.dash-page .no-slot-cta button:focus-visible {
  color: var(--tc-highlight, #d4c4a0) !important;
  border-color: var(--tc-accent, #c9a959) !important;
}

/* ============================================================================
 * "JETZT ZOCKEN" — der Weg vom Teaser an den Tisch
 * ----------------------------------------------------------------------------
 * Tim am 12.08.2026: "Wir sollten immer einen 'jetzt zocken' (oder so ähnlich)
 * Button haben, der den nächsten Termin mit einem freien Spielplatz pro System
 * anzeigt."
 *
 * Der Knopf steht ueber dem Hub-Shortcut, nicht darunter: "Ich will spielen"
 * ist der haeufigere Wunsch als "Ich will meinen Kader ansehen". Er traegt den
 * Systemakzent, damit klar bleibt, an welchem Tisch der Platz frei ist.
 * ========================================================================== */

.dash-sys__zocken {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  width: 100%;
  margin-top: var(--tc-space-3, 12px);
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--teaser-accent, #a1917a) 40%, transparent);
  border-radius: var(--tc-radius-md, 8px);
  background: color-mix(in srgb, var(--teaser-accent, #a1917a) 10%, transparent);
  color: var(--tc-text-strong, #eee);
  font-family: inherit;
  font-size: 0.92rem;
  text-align: left;
  cursor: pointer;
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
}

.dash-sys__zocken:hover,
.dash-sys__zocken:focus-visible {
  background: color-mix(in srgb, var(--teaser-accent, #a1917a) 20%, transparent);
  border-color: var(--teaser-accent, #a1917a);
  outline: none;
}

.dash-sys__zocken:active { transform: translateY(1px); }

.dash-sys__zocken-icon {
  flex-shrink: 0;
  font-size: 1.25rem;
  line-height: 1;
}

.dash-sys__zocken-text {
  /* EINE ZEILE seit dem Umbau auf Systemzeilen (13.08.2026). Hier stand
     `flex-direction: column` mit `min-height: 2.1rem` — richtig fuer eine
     Kachel, in der Beschriftung und Zeitpunkt untereinander standen. In
     einer Zeile machte genau das die Zeile 86px hoch statt 54; ueber fuenf
     Systeme rund 160px allein durch den Umbruch. Gemessen bei 776px. */
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  font-weight: 600;
  white-space: nowrap;
}

/* ⚠️ DIE GEWICHTUNG WAR UMGEKEHRT (20.08.2026). Der Zeitpunkt stand als
   kleinste, blasseste Schrift HINTER der immergleichen Aufforderung „Jetzt
   zocken" — dabei ist er das Einzige, was sich von Zeile zu Zeile
   unterscheidet. Jetzt fuehrt er den Knopf an, die Aufforderung folgt als
   Zusatz. */
.dash-sys__zocken-wann {
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--tc-text-strong, #eee);
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
}

.dash-sys__zocken-tun {
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--tc-text-muted, #9e9e9e);
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-sys__zocken-pfeil {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 1.2rem;
  color: var(--tc-text-muted, #888);
}

/* Kein freier Platz: derselbe Knopf, aber ohne Akzent — er ist ein
   Notausgang, keine Einladung. */
.dash-sys__zocken--leer {
  border-color: var(--tc-border-subtle, rgba(255, 255, 255, 0.1));
  background: none;
  color: var(--tc-text-muted, #999);
  font-size: 0.85rem;
  font-weight: 400;
}

.dash-sys__zocken--leer:hover,
.dash-sys__zocken--leer:focus-visible {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--tc-border-strong, rgba(255, 255, 255, 0.2));
  color: var(--tc-text-default, #ddd);
}

/* ============================================================================
 * HIER STANDEN DIE FEINHEITEN DER SYSTEM-KACHEL (entfernt 13.08.2026)
 * ----------------------------------------------------------------------------
 * Zwei Container-Query-Bloecke (Kennzahlen zwei- bzw. dreispaltig ab 285 und
 * 460px), die Groessen des Icon-Medaillons, die Breit-Regel fuer Namen, und
 * die Zweispaltigkeit der Aktionsleiste ab 300px. Alles sorgfaeltig
 * ausgemessen — und alles Feinschliff an einem Muster, das der Aufgabe nicht
 * entsprach (siehe DIE SYSTEM-ZEILE weiter oben).
 *
 * Die einzige Regel, die den Umbau ueberlebt hat, ist die Haltung dahinter:
 * Ein System ohne Daten wird nicht ausgeblendet, sondern leiser. Sie steht
 * jetzt als .dash-sys-row.is-leer bei den Zeilen — denn wer ein System
 * angehakt, aber noch nichts darin gemacht hat, ist genau der, den dieser
 * Block hineinziehen soll.
 * ========================================================================== */


/* --- Kartenraster: auto-fit statt fester Spaltenzahlen -------------------
 *
 * Tims Entscheidung zu #270 am 12.08.2026.
 *
 * css/dashboard.css baut das Raster mit FESTEN Spaltenzahlen und drei
 * Umschaltpunkten: 4 Spalten, unter 1200px 2, unter ~900px 1. Jedes andere
 * Raster dieser Seite steht dagegen auf `auto-fit` mit `minmax` — mit
 * ausdruecklicher Begruendung weiter oben in dieser Datei.
 *
 * Der sichtbare Defekt sass bei 1200/1201px: Dort sprang die Kartenbreite
 * von rund 566px auf rund 277px. Am Schreibtisch wurden die Karten also
 * SCHMALER als auf dem Tablet — genau verkehrt herum.
 *
 * 300px als Minimum ist gemessen, nicht geraten: Darunter bricht die
 * Kopfzeile der Karte (Datumskachel 56px + Titel + Countdown) in eine
 * unbrauchbare Anordnung. Bei 1600px Seitenbreite ergibt das vier Spalten,
 * bei 1200px drei, auf dem Tablet zwei, am Handy eine — der Sprung
 * verschwindet, und die Karten wachsen gleichmaessig mit.
 *
 * Der Preis, den Tim mitentschieden hat: Die Kartenzahl pro Zeile ist nicht
 * mehr garantiert. Die "+N weitere"-Karte kann damit in einer eigenen Zeile
 * landen; das ist verkraftbar, weil sie ohnehin die unwichtigste ist.
 * ------------------------------------------------------------------------- */
.dash-page .events-card-grid {
  /* min(300px, 100%): siehe die ausfuehrliche Begruendung bei
     .dash-teaser-grid. Kurz: Die Untergrenze in minmax() ist ein harter
     Boden. Bei 320px Geraetebreite blieben 292px Inhalt, der 300er-Boden
     ragte also 8px hinaus — das war der seitliche Scroll, den Tim gemeldet
     hat. Nachgemessen bei 280 / 300 / 320 / 344 / 375 / 390px: Ueberstand
     jetzt ueberall 0. */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--tc-space-4, 16px);
}

/* --- Info-Zeile: umbrechen statt Wortstuempfe ---------------------------
 *
 * Tims Entscheidung zu #270: "Umbrechen lassen."
 *
 * `.card-row-info` und `.info-attendance` sind Flex ohne `flex-wrap`. Bei
 * 375px — und im Vierspalten-Raster am Schreibtisch sogar haeufiger, weil
 * die Karte dort nur rund 297px breit ist — presste das die Zeile auf 55px
 * Hoehe und zerlegte sie in "6 / kommen (2 / spielen) 1 / abwesend".
 *
 * Die feste `min-height: 38px` aus dashboard.css bleibt als UNTERgrenze
 * bestehen (sie haelt die Karten gleich hoch, wenn wenig drinsteht) — nur
 * die Deckelung durch `nowrap` faellt weg.
 * ------------------------------------------------------------------------- */
.dash-page .card-row-info {
  flex-wrap: wrap;
  row-gap: 4px;
  align-items: center;
}

.dash-page .info-attendance {
  flex-wrap: wrap;
  row-gap: 2px;
  min-width: 0;
}

/* ============================================================================
 * WER HAT ZUGESAGT — Gesichter auf der Terminkarte
 * ----------------------------------------------------------------------------
 * Taskwerk #277, Tims Freigabe am 12.08.2026. Bis zu vier Zugesagte als
 * Avatar, darueber hinaus "+N". Die Avatare selbst sind `tc-avatar--sm` aus
 * der Library — hier steht nur, was die Terminkarte ergaenzt: das Ueberlappen
 * und der Statusrand.
 *
 * Ueberlappend statt nebeneinander, weil die Info-Zeile schmal ist: Vier
 * getrennte 28px-Kreise plus Abstaende kosten 136px, ueberlappend 82px. In
 * einer 300px-Karte ist das der Unterschied zwischen "passt" und "bricht um".
 * ========================================================================== */

.evt-faces {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  /* Gleicht die Ueberlappung des letzten Avatars aus, damit der Text
     dahinter nicht 8px zu nah steht.
     Hier stand zuerst `.evt-faces .evt-face:last-of-type { margin-right }`
     — und das griff am falschen Element: Letztes <span> im Container ist
     die unsichtbare Screenreader-Zeile, nicht der letzte Avatar. Die Regel
     setzte den Abstand also an etwas, das gar keine Breite hat. */
  margin-right: var(--tc-space-2, 8px);
}

.evt-face {
  margin-right: -8px;               /* Ueberlappung */
  border: 2px solid var(--tc-bg-surface-2, #1c1a18);
  box-sizing: content-box;
}

/* Der zuletzt Zugesagte liegt oben — sonst schneidet der naechste ihn an. */
.evt-faces .evt-face:nth-child(1) { z-index: 4; }
.evt-faces .evt-face:nth-child(2) { z-index: 3; }
.evt-faces .evt-face:nth-child(3) { z-index: 2; }
.evt-faces .evt-face:nth-child(4) { z-index: 1; }

/* Statusrand als Zugabe — die Aussage selbst steht im title und in der
   sr-only-Zeile, nie allein in der Farbe (#270). */
.evt-face.ist-spielend { border-color: var(--tc-success, #4ade80); }
.evt-face.ist-chillend { border-color: var(--tc-warning, #ff9800); }
.evt-face.ist-remote   { border-color: #7289da; }

.evt-face--rest {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--tc-radius-full, 9999px);
  background: rgba(255, 255, 255, 0.08);
  color: var(--tc-text-muted, #999);
  font-size: 0.68rem;
  font-weight: 700;
}

/* --- Countdown: läuft gerade / vorbei / bald ----------------------------
 *
 * Taskwerk #274, 12.08.2026. Der Countdown kannte nur "N Tage" und "Heute" —
 * ein Termin, der um 23:00 endete, stand bis Mitternacht als "Heute" an der
 * prominentesten Stelle der Seite. Jetzt fünf Zustände; hier bekommen drei
 * davon ihre Farbe.
 *
 * Die Aussage steht immer im TEXT ("läuft", "vorbei", "in 30 Min."), die
 * Farbe ist Zugabe — nach der Entscheidung aus #270 darf nichts allein in
 * der Farbe stecken.
 * ---------------------------------------------------------------------- */

.dash-page .card-countdown.ist-live .countdown-value,
.dash-page .card-countdown.ist-live .countdown-label,
.dash-page .row-countdown.ist-live .countdown-value,
.dash-page .row-countdown.ist-live .countdown-label {
  color: var(--tc-success, #4ade80);
}

/* Ein laufender Abend darf ruhig pulsieren — er ist der einzige Zustand,
   bei dem man JETZT etwas tun kann. */
.dash-page .card-countdown.ist-live .countdown-value {
  animation: dash-cd-puls 2.4s ease-in-out infinite;
}

@keyframes dash-cd-puls {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

.dash-page .card-countdown.ist-bald .countdown-label,
.dash-page .row-countdown.ist-bald .countdown-label {
  color: var(--tc-warning, #ff9800);
  /* "in 30 Min." ist länger als "Tage" — sonst bricht es um. */
  white-space: nowrap;
  font-size: 0.6rem;
}

/* Vorbei: zurückgenommen, aber nicht unlesbar. Die Karte bleibt bis
   Mitternacht stehen, sie soll nur nicht mehr rufen. */
.dash-page .card-countdown.ist-vorbei,
.dash-page .row-countdown.ist-vorbei {
  opacity: 0.55;
}

@media (prefers-reduced-motion: reduce) {
  .dash-page .card-countdown.ist-live .countdown-value { animation: none; }
}

/* --- Abgesagte Termine: sichtbar, aber erkennbar erledigt ---------------
 *
 * Taskwerk #271, 12.08.2026. Abgesagte Termine verschwanden bisher spurlos —
 * an sieben Stellen wurden sie herausgefiltert, eine Darstellung dafuer gab
 * es nicht. Wer zugesagt hatte, sah den Termin schlicht nicht mehr.
 *
 * Jetzt bleiben Absagen der naechsten sieben Tage stehen. Sie muessen auf den
 * ersten Blick als erledigt lesbar sein, ohne die Karte unleserlich zu
 * machen: gedaempft und mit durchgestrichenem Titel, aber nicht so blass,
 * dass man das Datum nicht mehr entziffert.
 * ---------------------------------------------------------------------- */

.dash-page .event-card.is-cancelled {
  opacity: 0.72;
  border-left-color: var(--tc-text-muted, #888);
}

.dash-page .event-card.is-cancelled .card-title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  color: var(--tc-text-muted, #999);
}

/* Der Countdown zaehlt auf etwas herunter, das nicht stattfindet — er wird
   deshalb zurueckgenommen statt entfernt (die Karte behaelt ihr Raster). */
.dash-page .event-card.is-cancelled .card-countdown { opacity: 0.45; }

/* Kein Hover-Anheben: Die Karte laedt nicht mehr zum Mitmachen ein. */
.dash-page .event-card.is-cancelled:hover { transform: none; box-shadow: none; }

.dash-page .evt-cancel-badge {
  position: absolute;
  top: -1px;
  left: 15px;
  z-index: 2;
}

/* --- Pathfinder: Charakterportraits und das Schicksal -------------------
 *
 * 12.08.2026, zwei Rueckmeldungen von Tim in einem Zug:
 *   "Bei Pathfinder entweder die Charaktere und deren Profilbilder ODER
 *    die Spieler mit Profilbild. Mir werden gerade Chris und Rost
 *    angezeigt. Aber Chris spielt Rost."
 *   "Wie stellst du mich denn bei Pathfinder dar? 'das Schicksal'? Denn
 *    sonst bin ich als Dungeon Master nicht in der Liste."
 *
 * Entschieden fuer die Charaktere — am Tisch sind sie die Identitaet, und
 * diese Zeile kann etwas, was die Gesichterreihe nicht kann: Sie zeigt
 * auch, wer noch NICHT zugesagt hat. Die generische Gesichterreihe
 * entfaellt auf Pathfinder-Karten deshalb ganz.
 * ---------------------------------------------------------------------- */

.dash-page .pf-char-pip__bild {
  width: 18px;
  height: 18px;
  border-radius: var(--tc-radius-full, 9999px);
  object-fit: cover;
  vertical-align: -4px;
  /* Wer nicht zugesagt hat, wird gedaempft — aber nicht unkenntlich. Die
     Aussage selbst steht im Text und in der Screenreader-Zeile (#270). */
}

.dash-page .pf-char-pip.absent .pf-char-pip__bild { filter: grayscale(1); opacity: 0.55; }

.dash-page .pf-char-pip__icon { font-size: 0.82rem; }

/* Das Schicksal hebt sich ab: Der Spielleiter ist kein siebter Held,
   sondern die Voraussetzung dafuer, dass ueberhaupt gespielt wird. */
.dash-page .pf-char-pip--gm {
  font-style: italic;
  letter-spacing: 0.02em;
}

.dash-page .pf-char-pip--gm.present {
  background: rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.14);
  border-color: rgba(var(--tc-highlight-rgb, 212, 196, 160), 0.4);
  color: var(--tc-highlight, #d4c4a0);
}

/* ============================================================================
 * VERGANGENE TERMINE IM KALENDER-FENSTER
 * ----------------------------------------------------------------------------
 * Hierher gezogen am 12.08.2026 (Tim: "die vergangenen Termine ... packst du
 * in die Terminuebersicht"). Vorher standen sie als Aufklapper unter der
 * Dashboard-Terminliste — dort waren sie das Erste beim Herunterscrollen,
 * obwohl sie die unwichtigste Information der Seite tragen.
 *
 * Steht in dashboard-page.css und nicht in dashboard.css, weil es neu ist:
 * dashboard.css ist die Altlast, die schrittweise abgeloest wird (7522 Zeilen,
 * null tc-Token). Neues gehoert nicht mehr hinein.
 * ========================================================================== */

.cal-past {
  margin-top: var(--tc-space-4, 16px);
  padding-top: var(--tc-space-3, 12px);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.cal-past__kopf {
  display: flex;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  min-height: var(--tc-touch-min, 36px);
  cursor: pointer;
  list-style: none;
  font-family: var(--tc-font-display, 'Cinzel', serif);
  font-size: 0.86rem;
  color: var(--tc-text-muted, #999);
  transition: color 160ms ease;
}

.cal-past__kopf::-webkit-details-marker { display: none; }

.cal-past__kopf::after {
  content: '\203A';
  margin-left: auto;
  font-size: 1.2rem;
  line-height: 1;
  transform: rotate(90deg);
  transition: transform 200ms var(--tc-ease-out, ease);
}

.cal-past[open] .cal-past__kopf::after { transform: rotate(-90deg); }

.cal-past__kopf:hover,
.cal-past__kopf:focus-visible { color: var(--tc-highlight, #d4c4a0); outline: none; }

.cal-past__zahl {
  padding: 1px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  font-family: var(--tc-font-body);
  font-size: 0.72rem;
}

.cal-past__liste {
  margin-top: var(--tc-space-2, 8px);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Die Zeile traegt die Systemfarbe als linke Kante — dasselbe Muster wie die
   Terminkarte auf dem Dashboard, damit man Mordheim von AoS unterscheidet,
   ohne zu lesen. --evt-color kommt aus dashboard.css:83-89 ueber
   [data-event-type]. */
.cal-past__zeile {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--tc-space-2, 8px);
  padding: 7px 10px;
  border-left: 3px solid var(--evt-color, rgba(255, 255, 255, 0.12));
  border-radius: var(--tc-radius-sm, 6px);
  background: rgba(255, 255, 255, 0.02);
  font-size: 0.8rem;
  cursor: pointer;
  transition: background 140ms ease;
}

.cal-past__zeile:hover,
.cal-past__zeile:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: none;
}

.cal-past__zeile:focus-visible {
  box-shadow: 0 0 0 2px var(--tc-highlight, #d4c4a0);
}

.cal-past__datum {
  color: var(--tc-text-muted, #999);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cal-past__titel {
  color: var(--tc-text-default, #ddd);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.cal-past__zeile.ist-durchgestrichen .cal-past__titel {
  text-decoration: line-through;
  opacity: 0.6;
}

.cal-past__status {
  font-size: 0.72rem;
  white-space: nowrap;
}

/* Vier Zustaende, vier Farben — und jeder traegt zusaetzlich Text bzw. ein
   Symbol, damit die Aussage nicht allein in der Farbe steckt. */
.cal-past__status.ist-offen       { color: var(--tc-warning, #ff9800); }
.cal-past__status.ist-fertig      { color: var(--tc-success, #4ade80); }
.cal-past__status.ist-ruhig       { color: var(--tc-text-muted, #999); }
.cal-past__status.ist-ausgefallen { color: var(--tc-text-muted, #999); opacity: 0.7; }

/* Auf schmalen Fenstern faellt der Status in eine eigene Zeile, statt den
   Titel zu erdruecken. */
@media (max-width: 560px) {
  .cal-past__zeile {
    grid-template-columns: auto 1fr;
    row-gap: 2px;
  }
  .cal-past__status { grid-column: 2; }
}

@media (prefers-reduced-motion: reduce) {
  .cal-past__kopf::after,
  .cal-past__zeile { transition: none; }
}

/* Rücksetzer im Leerzustand der Terminliste (#270, 12.08.2026).
   Sieht aus wie ein Link, ist aber ein <button> — die Handlung aendert
   Zustand, sie navigiert nicht. */
.dash-page .dash-filter-reset {
  display: inline;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: var(--tc-highlight, #d4c4a0);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  transition: color var(--tc-motion-fast) var(--tc-ease-out);
}

.dash-page .dash-filter-reset:hover,
.dash-page .dash-filter-reset:focus-visible {
  color: var(--tc-text-strong, #eee);
}

/* Die Knoepfe standen vorher einzeln und brachten eigene Abstaende mit.
   In der gemeinsamen Zeile regelt das der Grid-Gap. */
.dash-sys__aktionen .dash-sys__zocken,

/* ============================================================================
 * MODALE FENSTER — Randabstaende und die Sicherheitszone unten
 * ----------------------------------------------------------------------------
 * Diese drei Regeln standen bis zum 12.08.2026 als <style>-Block im Kopf von
 * dashboard.html, jede mit !important. Der Zweck war richtig: Kopf und Koerper
 * des Modals sollen bis an den Rand reichen und ihre Abstaende selbst
 * mitbringen. Der Weg war es nicht.
 *
 * `.modal-content { padding: 0 !important }` hat naemlich den Safe-Area-Block
 * aus css/dashboard.css (Zeile ~3729) mit ueberstimmt — und der ist das
 * Einzige, was den Inhalt auf einem iPhone aus dem Home-Indikator heraushaelt.
 * Auf dem Geraet lief der untere Rand eines Termin-Modals also unter den
 * Balken. Am Schreibtisch war davon nichts zu sehen.
 *
 * Jetzt ohne !important, dafuer ueber den Body-Selektor spezifisch genug
 * (0,2,1 gegen 0,1,0 der Regeln in css-fixes.css und dashboard.css), und die
 * Sicherheitszone sitzt dort, wo nach dem Padding-Reset noch Platz dafuer ist:
 * am scrollenden Koerper.
 * ========================================================================== */
body.dash-page-body .modal-content {
  padding: 0;
}

body.dash-page-body .modal-header {
  padding: 16px 20px;
  margin: 0;
}

body.dash-page-body .modal-body {
  padding: 16px 20px;
}

@supports (padding: max(0px)) {
  body.dash-page-body .modal-body {
    padding-bottom: max(16px, env(safe-area-inset-bottom));
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }
}

/* ============================================================================
 * AN DER WERKBANK — seit 14.08.2026 in css/components/werkbank.css
 * Die Werkbank laeuft in derselben Fassung auch im Untergrund (Old Krenks
 * Raum), und der laedt diese Seitendatei nicht — deshalb Umzug, keine Kopie.
 * ========================================================================== */

/* ============================================================================
   DER PRANGER — der Streifen ueber dem Dashboard (15.08.2026)
   ----------------------------------------------------------------------------
   Er erscheint nur, wenn wirklich jemand eine Kopfgeld-Schuld offen hat. Die
   rote Fassung gilt nur fuer den Schuldner selbst: Fuer alle anderen ist es
   eine Neuigkeit, fuer ihn eine Aufforderung.
   ========================================================================== */

.dash-pranger {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  flex-wrap: wrap;
  padding: var(--tc-space-3, 12px) var(--tc-space-4, 16px);
  margin-bottom: var(--tc-space-4, 16px);
  border: 1px solid var(--tc-warning, #fbbf24);
  border-radius: var(--tc-radius-md, 8px);
  background: linear-gradient(90deg, rgba(251, 191, 36, 0.1), transparent 65%),
              var(--tc-bg-surface-1, #242424);
}

.dash-pranger.ist-ich {
  border-color: var(--tc-danger, #ef4444);
  background: linear-gradient(90deg, rgba(239, 68, 68, 0.14), transparent 65%),
              var(--tc-bg-surface-1, #242424);
}

.dash-pranger__icon { font-size: 1.5rem; line-height: 1; }

.dash-pranger__text {
  flex: 1 1 220px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--tc-text-default, #b0b0b0);
}

.dash-pranger__text strong { color: var(--tc-text-strong, #e0e0e0); }
.dash-pranger .tc-button { flex-shrink: 0; white-space: nowrap; text-decoration: none; }

/* ==========================================================================
   FAKTENSAMMLUNG (.dash-fk) — Taskwerk #330, 16.08.2026
   --------------------------------------------------------------------------
   Ersetzt die Ranglisten mit Umschalter. Aufbau von oben nach unten:
     1. die eigene Bilanz gross (Siegquote ueber ALLE Systeme)
     2. vier Kennzahl-Kacheln
     3. das Podium "diese Saison verdient" mit Spielerbildern
     4. die Abstandszeile

   Tim zu Fassung 2: "Gut aussehen tut das auch noch nicht." Die Antwort
   darauf sind drei Dinge: Spielerbilder statt Medaillen-Emoji auf grauen
   Kaesten, echter Kontrast zwischen Platz 1 und dem Rest, und eine grosse
   Zahl als Anker (die Siegquote) statt lauter gleich grosser Zeilen.

   Farben: Medaillen sind DATENfarben und bleiben hart (CLAUDE.md §9), alles
   uebrige zieht `--tc-accent` / `--tc-highlight` aus dem Theme.
   ========================================================================== */

/* ⚠️ KEIN EIGENES POLSTER (16.08.2026).
   Tim: "Der Bereich ist jetzt richtig gut, aber er laeuft auf mobile weniger
   breit als die anderen."

   Gemessen bei 375px: `.dash-fk` ist mit 347px genauso breit wie eine
   `.dash-sys-row` — der Abschnitt ist also NICHT schmaler. Schmaler war sein
   INHALT: 12px Polster hier plus 12px in `.dash-fk__bilanz` schoben ihn 24px
   vom Rand, waehrend die Systemzeilen mit ihren 12px auf 12px kommen. Zwei
   Bloecke mit gleicher Aussenkante, aber verschobener Innenkante lesen sich
   als unterschiedlich breit.

   Die Kinder bringen ihr Polster selbst mit (Bilanz-Box, Kacheln, Podium) —
   genau wie `.dash-sys-row`. Also hier keins.

   Beide Klassen im Selektor (0,2,0), weil `.dash-page .tc-hub__section`
   dieselbe Spezifitaet hat und sonst gewinnen koennte — dieselbe Vorsicht wie
   bei `.dash-untergrund.tc-hub__section` weiter oben. */
.dash-fk.tc-hub__section {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--tc-space-3, 12px);
}

/* Nur das Saison-Schild — der Abschnittstitel steht in dashboard.html.
   Bewusst ein <div>: Ein <header> bekommt hier von einer generischen Regel
   einen roten Verlauf verpasst (im Browser gemessen, im Quelltext unsichtbar). */
.dash-fk__kopf {
  display: flex;
  justify-content: flex-end;
  margin-bottom: calc(-1 * var(--tc-space-2, 8px));
}

.dash-fk__saison {
  font-size: 0.72rem;
  padding: 2px 9px;
  border-radius: var(--tc-radius-full, 999px);
  background: var(--tc-bg-surface-3);
  border: 1px solid var(--tc-border-subtle);
  color: var(--tc-text-muted);
  white-space: nowrap;
}

/* --- 1. Die eigene Bilanz ------------------------------------------------ */

.dash-fk__bilanz {
  display: flex;
  align-items: center;
  gap: var(--tc-space-3, 12px);
  padding: var(--tc-space-3, 12px);
  border-radius: var(--tc-radius-md, 8px);
  background: var(--tc-bg-surface-2);
  border: 1px solid var(--tc-border-subtle);
}

/* Die grosse Zahl ist der Anker der Kachel — sie darf die einzige sein. */
.dash-fk__quote {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 84px;
  padding: var(--tc-space-2, 8px);
  border-radius: var(--tc-radius-md, 8px);
  background: rgba(var(--tc-highlight-rgb), 0.08);
  border: 1px solid rgba(var(--tc-highlight-rgb), 0.22);
}

.dash-fk__quote-zahl {
  font-size: 1.7rem;
  font-weight: 800;
  line-height: 1.05;
  color: var(--tc-highlight);
  font-variant-numeric: tabular-nums;
}

.dash-fk__quote-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--tc-text-muted);
}

.dash-fk__bilanz-text { min-width: 0; flex: 1; }

.dash-fk__bilanz-zeile {
  margin: 0 0 2px;
  font-size: 0.84rem;
  color: var(--tc-text-default);
}

.dash-fk__bilanz-zeile strong { color: var(--tc-text-strong, #e0e0e0); }

.dash-fk__bilanz-saison {
  margin: 0;
  font-size: 0.78rem;
  color: var(--tc-text-muted);
}

.dash-fk__bilanz-saison strong { color: var(--tc-highlight); }
.dash-fk__bilanz-saison--still { font-style: italic; }

/* Ein Chip je System MIT Partien. Systeme ohne Partie erscheinen gar nicht —
   eine 0-%-Quote liest sich wie lauter Niederlagen. */
.dash-fk__syschips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--tc-space-2, 8px);
}

.dash-fk__syschip {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 2px 7px;
  border-radius: var(--tc-radius-full, 999px);
  background: var(--tc-bg-surface-3);
  border: 1px solid var(--tc-border-subtle);
  font-size: 0.74rem;
  color: var(--tc-text-default);
}

.dash-fk__syschip strong { color: var(--tc-text-strong, #e0e0e0); font-variant-numeric: tabular-nums; }
.dash-fk__sysicon { font-size: 0.85rem; }
.dash-fk__sysn { color: var(--tc-text-muted); font-size: 0.68rem; }

.dash-fk__bilanz--leer { display: block; }
.dash-fk__leer-titel { margin: 0 0 4px; font-size: 0.88rem; color: var(--tc-text-strong, #e0e0e0); }
.dash-fk__leer-text  { margin: 0; font-size: 0.78rem; line-height: 1.5; color: var(--tc-text-muted); }

/* --- 2. Die Kennzahl-Kacheln --------------------------------------------- */

/* ZWEI SPALTEN, nicht "so viele wie passen". Bei vier Kacheln und 140px
   Mindestbreite ergab auto-fit in der halben Dashboard-Spalte 3+1 — drei
   nebeneinander und eine allein darunter. Vier Kacheln wollen 2x2. */
.dash-fk__kacheln {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--tc-space-2, 8px);
}

.dash-fk__kachel {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--tc-space-2, 8px) 10px;
  border-radius: var(--tc-radius-sm, 6px);
  background: var(--tc-bg-surface-2);
  border: 1px solid var(--tc-border-subtle);
  border-left: 3px solid var(--tc-border-default);
  transition: border-color var(--tc-motion-fast, 120ms) ease;
}

.dash-fk__kachel.is-mine {
  border-left-color: var(--tc-highlight);
  background: rgba(var(--tc-highlight-rgb), 0.06);
}

.dash-fk__k-icon  { font-size: 0.95rem; line-height: 1; }
.dash-fk__k-label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
                    color: var(--tc-text-muted); }
.dash-fk__k-wert  { font-size: 1rem; font-weight: 700; color: var(--tc-text-strong, #e0e0e0);
                    font-variant-numeric: tabular-nums; }
/* Der Name verlinkt aufs Profil und mass 19px. inline-flex statt block,
   damit Ellipsis und Umbruchverhalten bleiben (#235). */
.dash-fk__k-wer   { font-size: 0.74rem; color: var(--tc-highlight); text-decoration: none;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
                    display: inline-flex; align-items: center;
                    min-height: var(--tc-touch-min, 36px); }
a.dash-fk__k-wer:hover { text-decoration: underline; }

/* --- 3. Das Podium ------------------------------------------------------- */

.dash-fk__unter {
  margin: 0 0 var(--tc-space-1, 4px);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--tc-text-muted);
}

.dash-fk__podium { padding-top: var(--tc-space-1, 4px); }

/* Das Bild ersetzt die graue Medaillenscheibe; die Medaille sitzt als kleine
   Plakette darauf. `profileImage` ueberlebt publicPlayers() (CLAUDE.md §7). */
.dash-fk__podium-bild { position: relative; display: inline-block; }

.dash-fk__avatar {
  display: block;
  width: 44px; height: 44px;
  border-radius: var(--tc-radius-full, 999px);
  overflow: hidden;
  background: var(--tc-bg-surface-3);
  border: 2px solid var(--tc-border-default);
}

.dash-fk__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.dash-fk__avatar--leer {
  display: flex; align-items: center; justify-content: center;
  font-size: 1.1rem; font-weight: 700; color: var(--tc-text-muted);
}

/* Platz 1 bekommt sichtbar mehr — das war der eigentliche Mangel an
   Fassung 2: drei gleich grosse Kaesten nebeneinander sind kein Treppchen. */
.tc-leaderboard__podium-place--first .dash-fk__avatar {
  width: 58px; height: 58px;
  border-color: #d4af37;                       /* Datenfarbe Gold (§9) */
  box-shadow: 0 0 12px rgba(212, 175, 55, 0.35);
}
.tc-leaderboard__podium-place--second .dash-fk__avatar { border-color: #c0c0c0; }
.tc-leaderboard__podium-place--third  .dash-fk__avatar { border-color: #cd7f32; }

.dash-fk__podium-medaille {
  position: absolute;
  right: -3px; bottom: -3px;
  font-size: 0.9rem;
  line-height: 1;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
}

.dash-fk .tc-leaderboard__name  { font-size: 0.82rem; }
.dash-fk .tc-leaderboard__value { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.dash-fk .tc-leaderboard__podium-place--first .tc-leaderboard__value { font-size: 1.3rem; }
.dash-fk .tc-leaderboard__meta  { font-size: 0.7rem; color: var(--tc-text-muted); }
.dash-fk__einheit { font-size: 0.62em; margin-left: 2px; color: var(--tc-text-muted); }

/* --- 4. Die Abstandszeile ------------------------------------------------ */

.dash-fk__ziel {
  margin: var(--tc-space-2, 8px) 0 0;
  padding: 8px 10px;
  border-radius: var(--tc-radius-sm, 6px);
  background: var(--tc-deco-warm-bg);
  border: 1px solid var(--tc-deco-warm-border);
  color: var(--tc-deco-warm-text);
  font-size: 0.82rem;
  text-align: center;
}

.dash-fk__ziel strong { color: var(--tc-highlight); }
.dash-fk__ziel--fuehrung,
.dash-fk__ziel--still { color: var(--tc-text-muted); }

/* Am Handy stapelt die Bilanz, sonst quetscht die grosse Zahl den Text. */
@media (max-width: 560px) {
  .dash-fk__bilanz { flex-direction: column; align-items: stretch; text-align: center; }
  .dash-fk__quote  { min-width: 0; }
  .dash-fk__syschips { justify-content: center; }
  .dash-fk__kacheln { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ==========================================================================
   MEINE SPIELE ALS WEGWEISER (Taskwerk #336, 16.08.2026)
   --------------------------------------------------------------------------
   Tim: "Und wir nehmen Absprung."

   Damit entfallen die Kennzahlen in der Zeile — und mit ihnen sechs Regeln,
   deren Markup nicht mehr entsteht (__fakten, __fakt, __wert, __label,
   __leer, .is-leer). An ihre Stelle tritt EINE Zeile: was hinter dem Link
   liegt. Die Zahlen sind nicht weg, sie stehen in den Hubs; die
   vergleichbaren stehen seit dem 16.08. in "Bilanz & Wertung" darueber.
   ========================================================================== */

/* ⚠️ DER UNTERTITEL SCHRUMPFT, DIE AKTIONEN NICHT.
   Erster Entwurf gab beiden nach — und dann fraß der Wegweiser-Text dem
   "Jetzt zocken" den Platz weg, bis vom Termin "Donne…" übrigblieb. Genau
   der Mangel, den #336 benannt hatte ("Das Datum ist die Information, die
   abgeschnitten wird"), nur an neuer Stelle. Der Termin ist die Zusage, der
   Untertitel nur die Beschreibung — also schrumpft der Untertitel. */
/* ⚠️ DIE WEGBESCHREIBUNG FAELLT WEG, DIE STATUSMELDUNG BLEIBT (20.08.2026).
   „Roster, Chronik, Gefallene & Untergrund" beantwortet keine Frage, die man
   VOR dem Klick hat — der Link daneben sagt schon „Zur Kriegsbande". Am Handy
   kostete dieser Satz eine eigene Zeile je System; bei vier Systemen war das
   ein Viertel des Blocks fuer eine Aufzaehlung, die niemand liest.

   „Noch keine Armeeliste eingereicht." dagegen nennt den fehlenden Schritt
   und steht direkt neben dem Termin, an dem er gebraucht wird. Diese Zeile
   traegt `is-ruft` und bleibt — sichtbar auf jeder Breite. */
.dash-sys-row:not(.is-ruft):not(.dash-sys-row--einladung) .dash-sys-row__sub {
  display: none;
}

.dash-sys-row__sub {
  flex: 1 1 6rem;
  min-width: 0;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--tc-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ⚠️ DER GESTRICHELTE RAHMEN MUSSTE WEG (20.08.2026).
   Gedacht war er als „hier geht es weiter" — gelesen wurde er als
   Fehlerzustand: Ein gestrichelter Kasten sieht auf dieser Plattform sonst
   nach Platzhalter oder Warnung aus, und er lief um die GANZE Zeile statt um
   eine leere Flaeche. Zusammen mit zwei Knoepfen auf voller Breite wirkte der
   Block laut fuer eine Sache, die niemand vermisst: ein System, das man nie
   gespielt hat.

   Jetzt eine ruhige Zeile wie die anderen, nur gedaempft. Sie soll einladen,
   nicht alarmieren. */
.dash-sys-row--einladung {
  border-left-color: var(--tc-border-subtle, rgba(255, 255, 255, 0.12));
  background: transparent;
  opacity: 0.82;
}

.dash-sys-row--einladung:hover { opacity: 1; }

.dash-sys-row--einladung .dash-sys-row__sub {
  flex: 1 1 auto;
  font-style: italic;
}

.dash-sys-row--einladung .dash-sys-row__hub { white-space: nowrap; }

@media (max-width: 560px) {
  .dash-sys-row__sub { flex-basis: 100%; }
}

/* Der Termin darf nicht abgeschnitten werden — er ist der Grund, warum der
   Knopf da ist. Der Knopf darf dafuer aber auch nicht ueber den Nachbarn
   laufen: `flex: 0 0 auto` allein liess den Block ueberbreit werden, statt
   umzubrechen. Also darf er umbrechen (zwei Zeilen sind besser als eine
   Ueberlappung), und der Untertitel gibt zuerst nach. */
.dash-sys-row__aktionen {
  flex: 0 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
  min-width: 0;
}
.dash-sys-row__aktionen .dash-sys__zocken-wann { overflow: visible; text-overflow: clip; }
.dash-sys-row__aktionen .dash-sys__zocken { flex: 0 0 auto; }

/* Die Einladungszeile stapelt bewusst: Satz oben, Handlungen darunter.
   `nowrap` stand hier zuerst — und als der "Runde anfragen"-Knopf dazukam,
   ueberlappte er den Hub-Link, weil zwei Kinder ohne Umbruch mehr Platz
   brauchen als die Zeile hat. Ein voller Umbruch ist hier ohnehin richtig:
   Diese Zeile hat kein System-Logo links, also auch keine Spalte, an der
   sich etwas ausrichten muesste. */
/* ⚠️ BLOCK STATT FLEX — nach drei Anlaeufen.
   Die Einladungszeile erbt das Flex-Layout der Systemzeile, und das ist auf
   "Marke links, Aktionen rechts" gebaut. Hier gibt es keine Marke, dafuer
   drei Kinder in den Aktionen. Ergebnis der Vererbung, gemessen: der
   Anfrage-Knopf auf 26px gequetscht, der Hub-Link 136px breit in einem
   126px-Container — also darueber hinaus. Jeder Flex-Eingriff hat nur die
   naechste Quetschung erzeugt.

   Als Block ist die Zeile das, was sie inhaltlich ist: ein Satz mit
   Handlungen darunter. Kein Ausrichten an einer Spalte, die es nicht gibt. */
.dash-sys-row--einladung { display: block; }
.dash-sys-row--einladung .dash-sys-row__sub {
  margin-bottom: var(--tc-space-2, 8px);
}
.dash-sys-row--einladung .dash-sys-row__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tc-space-2, 8px);
  justify-content: flex-start;
  margin-left: 0;
}
.dash-sys-row--einladung .dash-sys-row__aktionen > * { flex: 0 0 auto; }

/* DIE RUF-ZEILE: Termin steht, Inhalt fehlt (Taskwerk #336, 16.08.2026)
   Tim: "Bei ToW steht schon ein Termin an. Hier muesste doch besonders
   angeregt werden?" — also nicht leiser als eine volle Zeile, sondern
   lauter. Warm hinterlegt wie die Abstandszeile in "Bilanz & Wertung";
   der Untertitel nennt den fehlenden Schritt statt der Wegbeschreibung. */
.dash-sys-row.is-ruft {
  background: var(--tc-deco-warm-bg);
  border-color: var(--tc-deco-warm-border);
}

/* ⚠️ DER HINWEIS WAR EIN SATZ, KEINE HANDLUNG (20.08.2026, Tim: „der Hinweis
   ist cool, aber das müsste dann besser aussehen").

   Er stand als kursiver Fliesstext unter der Zeile — dieselbe Form, in der
   darueber „Roster, Chronik, Gefallene" stand. Also sah eine Aufforderung aus
   wie eine Wegbeschreibung, und beides ging im selben Grau unter.

   Jetzt ein Chip mit Zeichen: abgesetzt, in gedaempfter Warnfarbe, nicht
   kursiv. Er sagt „hier fehlt noch etwas" und steht direkt neben dem Weg
   dorthin — der Hub-Link derselben Zeile heisst ohnehin schon „Zu den
   Listen". Ein eigener Link waere ein zweiter Link auf dasselbe Ziel und
   fuer Screenreader eine Dopplung.

   Das Zeichen als CSS-Escape, nicht als Emoji im Quelltext: In `content:`
   ist das die einzige Stelle in CSS, an der ein Encoding-Fehler im Browser
   sichtbar wird (CLAUDE.md §6). */
.dash-sys-row.is-ruft .dash-sys-row__sub {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  padding: 3px 10px 3px 8px;
  border: 1px solid var(--tc-deco-warm-border);
  border-radius: 999px;
  background: var(--tc-deco-warm-bg);
  color: var(--tc-deco-warm-text);
  font-style: normal;
  font-weight: 600;
  overflow: visible;
}

.dash-sys-row.is-ruft .dash-sys-row__sub::before {
  content: '\26A0';
  font-size: 0.9em;
  line-height: 1;
}

/* "Du bist dabei" — der dritte Zustand des Zocken-Knopfs. Kein Angebot mehr,
   sondern eine Zusage: gruen wie jede erledigte Sache auf dieser Plattform
   (Datenfarbe, CLAUDE.md §9), und ruhiger als "Jetzt zocken". */
.dash-sys__zocken--dabei {
  border-color: rgba(74, 222, 128, 0.45);
  color: var(--tc-text-default);
}
.dash-sys__zocken--dabei .dash-sys__zocken-icon { color: #4ade80; }
.dash-sys__zocken--dabei:hover,
.dash-sys__zocken--dabei:focus-visible { border-color: #4ade80; }

/* Der Mutmacher-Halbsatz in der Einladungszeile — er traegt die Aussage,
   der Satz davor nur die Feststellung. Deshalb heller als sein Umfeld. */
.dash-sys-row__mut { color: var(--tc-highlight); font-style: normal; }

/* ⚠️ KEIN STRETCHED LINK IN DER EINLADUNGSZEILE.
   `.dash-sys-row__hub::after` legt `inset: 0` ueber die GANZE Zeile — das ist
   der Trick, der eine Systemzeile als Ganzes anklickbar macht (Tim: "Das soll
   mich ja in die Spielsysteme reinziehen"). Er setzt aber genau EINEN Link je
   Zeile voraus.

   In der Einladung stehen zwei Wege plus der Anfrage-Knopf. Dort lagen damit
   drei unsichtbare Flaechen uebereinander: Der letzte Link im Markup gewann,
   und "Runde anfragen" war nicht mehr zu treffen. Im Quelltext unsichtbar —
   nur ueber getBoundingClientRect() aufgefallen. */
.dash-sys-row--einladung .dash-sys-row__hub::after { content: none; }
.dash-sys-row--einladung .dash-sys-row__hub { position: relative; z-index: 1; }


/* ----------------------------------------------------------------------------
   EHRENTITEL IN „MEIN FORTSCHRITT" (20.08.2026)
   ----------------------------------------------------------------------------
   Direkt unter dem Rang, weil beides dieselbe Frage beantwortet: was bin ich
   hier. Der Rang waechst mit, der Ehrentitel ist eingefroren.

   Drei von zwanzig Spielern haben einen — deshalb keine Ueberschrift und kein
   Platzhalter, der Block faellt sonst ersatzlos weg.
   -------------------------------------------------------------------------- */
.dash-fortschritt__ehren {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 var(--tc-space-3, 12px);
}

.dash-fortschritt__ehre {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border: 1px solid var(--tc-accent, #c9a959);
  border-radius: 999px;
  background: rgba(var(--tc-accent-rgb, 201, 169, 89), 0.12);
  font-size: 0.78rem;
  color: var(--tc-highlight, #e8cf9a);
  cursor: help;
}

/* ===================================================================
   DIE FRISCH GEAENDERTE TERMINKARTE (22.08.2026, Taskwerk #349 Teil 2)
   -------------------------------------------------------------------
   ⚠️ NICHT DIE GANZE LISTE EINBLENDEN. Der naheliegende Fix waere gewesen,
   `dash-teaser-auf` auch auf die Terminliste zu legen — die Animation steht
   direkt daneben. Die Systemzeilen rendern aber EINMAL beim Laden, diese
   Liste bei jeder Zusage, jeder Absage, jedem Filterklick
   (js/ui/dashboard-events.js setzt `innerHTML`). Alle Karten bei jedem Klick
   neu einfliegen zu lassen ist schlechter als der harte Wechsel — und genau
   die Sorte „Verbesserung", die man hinterher wieder ausbaut.

   Die nuetzliche Rueckmeldung ist eine andere: nicht „die Liste ist neu",
   sondern „deine Zusage ist angekommen". Also genau EINE Karte, kurz.

   Gefaerbt wird mit dem Theme-Akzent — es ist eine Aufmerksamkeitsgeste,
   keine Aussage ueber die Daten (CLAUDE.md §9). */
.event-card.is-frisch {
  animation: eventKarteFrisch 1300ms var(--tc-ease-out, ease-out) 1;
}

@keyframes eventKarteFrisch {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tc-accent) 55%, transparent); }
  18%  { box-shadow: 0 0 0 4px color-mix(in srgb, var(--tc-accent) 35%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tc-accent) 0%, transparent); }
}

/* ⚠️ NICHT `animation: none` (CLAUDE.md §9): Dabei faellt auch der Endzustand
   weg. Hier ist der Endzustand zwar „kein Schein", aber die Vorlage gilt
   trotzdem — wer sie einmal bricht, bricht sie beim naechsten Mal wieder. */
@media (prefers-reduced-motion: reduce) {
  .event-card.is-frisch {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    animation-delay: -1ms;
    /* Statt der Bewegung ein kurzer, ruhiger Rand — die Rueckmeldung soll
       nicht ganz verschwinden, nur nicht mehr pulsieren. */
    outline: 2px solid color-mix(in srgb, var(--tc-accent) 45%, transparent);
    outline-offset: 2px;
  }
}
