/* ═══════════════════════════════════════════════════════════════════════════
   DORF V2 — neues Desktop-Layout

   ALLES in dieser Datei steht in @media(min-width:641px). Unterhalb davon
   greift keine einzige Regel, damit die Mobilansicht unveraendert bleibt —
   isMobile() im Spiel zieht dieselbe Grenze (<=640px).

   Sie laedt NACH style.css und ueberschreibt gezielt. Die Bestandsdatei
   (rund 700 KB) bleibt unangetastet; faellt diese Datei weg, ist das alte
   Layout sofort zurueck.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (min-width: 641px) {

  /* ── Farbwerte ─────────────────────────────────────────────────────────
     Greifen die Token des Spiels ab, damit Hell und Dunkel automatisch
     mitgehen. Eigene Werte gaebe es sonst doppelt. */
  :root {
    --dv2-nav-h: 40px;
    --dv2-luft: 14px;
    /* Feste Buehnenhoehe. Der Chat richtet sich danach aus, deshalb muss sie
       an einer Stelle stehen und nicht zweimal gerechnet werden. */
    --dv2-szene-h: min(62vh, 660px);
    /* Flaechen, die WEISSE Schrift tragen: gemessen liefert --primary nur
       4,28:1, --primary-d dagegen 6,07:1. Fuer das Abzeichen fehlt dem Spiel
       ein dunkles Rot - --red (#ef4444) kommt mit Weiss nur auf 3,76:1. */
    --dv2-auf-weiss: var(--primary-d, #3a56d4);
    --dv2-warn-fest: #c62828;   /* Weiss darauf: 5,6:1 */
    /* Schrift auf der hellen Primaerflaeche (--primary-l). */
    --dv2-primary-text: var(--primary-d, #3a56d4);   /* hell: 5,4:1 */
  }

  /* ── Kopfleiste ────────────────────────────────────────────────────────
     Bewusst schmal: sie ist eine Navigationsleiste, keine Buehne. Die Tiefe
     steckt im Megamenue. */
  /* Im Dunkelmodus liegt --primary-l dunkel; dort traegt der hellere Ton. */
  [data-theme="dark"] { --dv2-primary-text: var(--primary, #6b84f8); }

  .topnav { position: relative; z-index: 60; }

  /* Die Kopfleiste ist EINE Flexzeile: Logo, Hauptmenue, dann die rechte
     Gruppe (Gold, Sprache, Design, Profil). Die beiden auto-Raender saugen den
     freien Platz auf und teilen ihn gleichmaessig links und rechts vom Menue -
     das Menue rueckt damit zur Mitte, die rechte Gruppe an den Rand. Ohne sie
     klebte das Menue direkt am Logo. */
  .dv2-nav { display: flex; align-items: center; gap: 2px; min-width: 0; margin-inline: auto; }

  .dv2-navbtn {
    position: relative; display: flex; align-items: center; gap: 7px;
    height: var(--dv2-nav-h); padding: 0 clamp(9px, .75vw, 14px);
    border: 0; background: none; border-radius: 10px; cursor: pointer;
    font: inherit; font-size: .86rem; font-weight: 700; color: var(--text2);
    white-space: nowrap; transition: background .15s, color .15s;
  }
  /* Sichtbare Groesse bleibt, die Trefferflaeche waechst unsichtbar auf 44px. */
  .dv2-navbtn::after {
    content: ''; position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    width: max(100%, 44px); height: max(100%, 44px);
  }
  .dv2-navbtn:hover { background: var(--bg2, rgba(0,0,0,.05)); color: var(--text); }
  .dv2-navbtn:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

  /* Der aktive Ort ist gefuellt, das GEOEFFNETE Menue zusaetzlich umrandet —
     ohne diesen Unterschied weiss man nicht mehr, wo man gerade ist. */
  .dv2-navbtn.ist-aktiv { background: var(--primary-l, rgba(79,110,247,.12)); color: var(--dv2-primary-text); font-weight: 800; }
  .dv2-navbtn.ist-offen {
    background: var(--primary-l, rgba(79,110,247,.12)); color: var(--dv2-primary-text);
    box-shadow: inset 0 0 0 1px var(--primary);
  }
  .dv2-navbtn .dv2-ico { width: 1.15em; height: 1.15em; flex-shrink: 0; }
  .dv2-navbtn .dv2-ico:last-of-type { width: .8em; height: .8em; opacity: .6; transition: transform .18s; }
  .dv2-navbtn.ist-offen .dv2-ico:last-of-type { transform: rotate(180deg); opacity: 1; }

  .dv2-ico { fill: none; stroke: currentColor; stroke-width: 1.9;
             stroke-linecap: round; stroke-linejoin: round; }

  /* Die Seitenleiste traegt die Navigation nicht mehr — sie steht oben.
     Zwei Klassen im Selektor sind noetig: style.css setzt
     .sb-nav-section.sb-nav-groups{display:flex!important}, und bei gleichem
     !important entscheidet weiterhin die Spezifitaet. */
  .sb-nav-section,
  .sb-nav-section.sb-nav-groups { display: none !important; }


  /* ── Seitenspalte nach dem Entwurf ─────────────────────────────────────
     Im Entwurf steht der Held mittig: grosses rundes Portrait, Name darunter,
     dann Level mit EXP-Balken und die Werteleisten. Der EXP-Balken wird aus
     der Kopfleiste hierher UMGEHAENGT (siehe dv2ExpInDieSpalte) - dort gehoert
     er nicht hin und machte die Leiste unnoetig hoch. */
  .sb-char-top {
    flex-direction: column; align-items: center; text-align: center; gap: 10px;
  }
  /* Groesse und Ring kommen vom Heldenrahmen - siehe .dv2-portrait. */
  .sb-avatar img { width: 100%; height: 100%; object-fit: cover; object-position: center 15%; }
  .sb-char-info { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 4px; }
  .sb-char-name-row { flex-wrap: wrap; justify-content: center; gap: 6px; }
  .sb-char-name { font-size: 1.35rem; font-weight: 800; }
  /* Rasse und Klasse stehen auf dem Charakterbogen - in der Spalte sind sie
     Beiwerk. Die Zeile bleibt im DOM (updateUI schreibt hinein) und wird nur
     eingeblendet, wenn sie etwas zu TUN gibt: ab Stufe 10 ohne gewaehlte
     Klasse traegt sie den Hinweis "Klasse waehlen" (siehe dv2SpalteWerte). */
  .sb-class-row { display: none; }
  .sb-class-row.dv2-klassenwahl {
    display: block; font-size: .84rem; font-weight: 700; color: var(--text2);
  }
  .sb-class-row.dv2-klassenwahl .sb-chip-race { display: none; }
  /* Gold steht oben rechts in der Kopfleiste (siehe dv2SpalteAufbauen).
     In der Spalte waere es dieselbe Zahl ein zweites Mal. */
  .sb-gold-row { display: none; }

  /* Der umgehaengte EXP-Balken sitzt zwischen Charakterblock und Werteleisten. */
  .sidebar .topnav-xp {
    display: flex; flex-direction: column; gap: 5px;
    width: 100%; margin: 2px 0 2px; padding: 0;
  }
  .sidebar .topnav-xp-row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    font-size: .78rem; font-weight: 700; color: var(--text2);
  }
  /* Die Stufe steht am Portrait. Neben dem EXP-Balken waere sie doppelt -
     wie weit es bis zur naechsten reicht, zeigt der Balken selbst. */
  .sidebar .topnav-xp .lvl-badge { display: none; }
  .sidebar .topnav-xp .bar-track { width: 100%; height: 7px; border-radius: 50px; }

  /* Kompaktere Wertekacheln - im Entwurf traegt die Spalte vor allem Balken. */
  .sb-quick-stats { gap: 6px; }
  .sb-qs-cell { padding: 7px 4px; }


  /* Portrait im Heldenrahmen (assets/dorf/heldenrahmen.webp).
     ALLE Prozentwerte hier sind am Bild GEMESSEN, nicht geschaetzt:
     Innenkreis 79% der Breite, Kreismitte x 50.9% / y 47.7%,
     Schildmitte x 50.7% / y 84%. Wer den Rahmen austauscht, muss sie
     neu messen - tools/ hat dafuer kein Werkzeug, es war eine
     Alpha-/Farbanalyse von Hand. */
  .dv2-portrait {
    position: relative; flex: none;
    width: clamp(150px, 13vw, 196px);
    aspect-ratio: 361 / 347;
    cursor: pointer;
    transition: transform .16s;
  }
  .dv2-portrait:hover { transform: translateY(-3px); }
  .dv2-portrait:focus-visible {
    outline: 3px solid var(--primary); outline-offset: 4px; border-radius: 50%;
  }
  .dv2-portrait .sb-avatar {
    position: absolute; left: 50.9%; top: 47.7%; transform: translate(-50%, -50%);
    width: 79%; height: auto; aspect-ratio: 1;
    /* Der Rahmen bringt Rand und Schatten mit - der alte Ring muss weg. */
    border: 0; box-shadow: none;
    border-radius: 50%; overflow: hidden;
    background: var(--primary-l);
  }
  .dv2-portrait-rahmen {
    position: absolute; inset: 0; width: 100%; height: 100%;
    z-index: 2; pointer-events: none;
    filter: drop-shadow(0 6px 14px rgba(38, 53, 74, .18));
  }
  /* Die Stufe steht AUF dem blauen Schild des Rahmens. Deshalb kein eigener
     Hintergrund und keine Umrandung mehr - beides verdeckte vorher den
     Charakter. */
  .dv2-portrait #sbLvlPill {
    /* 52%/87% statt der gemessenen Schildmitte 50.7%/84%: von Minni im
       laufenden Spiel nachjustiert. Das Schild ist kein exaktes Rechteck -
       die Zahl sitzt im sichtbaren Feld hoeher und einen Hauch rechts. */
    position: absolute; left: 52%; top: 87%; transform: translate(-50%, -50%);
    z-index: 3; min-width: 0; width: auto; height: auto; padding: 0;
    display: block; border: 0; background: none; box-shadow: none;
    font-size: clamp(.84rem, 1.05vw, 1rem); font-weight: 900; line-height: 1;
    color: #fff; text-shadow: 0 1px 2px rgba(20, 40, 90, .5);
    pointer-events: none;
  }

  /* Zierlinie aus dem gelieferten Asset (assets/dorf/zierlinie.webp,
     erzeugt von tools/make-dorf-webp.php aus asset-line4.png). Vorher stand
     hier ein nachgezeichneter SVG-Schwung - der traf die Vorlage nicht. */
  .dv2-trenner {
    height: 20px; margin: 6px 0 8px; flex: none;
    background: no-repeat center / contain url("../assets/dorf/zierlinie.webp");
  }
  /* Die Linie ist dunkel gezeichnet - im Nachtmodus umkehren, sonst
     verschwindet sie auf dem dunklen Grund. */
  [data-theme="dark"] .dv2-trenner { filter: invert(1) brightness(1.6) opacity(.75); }

  /* AP als dritte Balkenzeile, golden wie im Entwurf. Die Kachel bleibt als
     Wertequelle im DOM, wird aber nicht mehr angezeigt. */
  .dv2-ap-fill { background: linear-gradient(90deg, #d98f28, #e2a33c); }

  /* Im Entwurf steht ueber jedem Balken eine Zeile aus Symbol, Name und Zahl. */
  .sb-bars { gap: 9px; }
  .sb-bar-row {
    display: grid; grid-template-columns: auto 1fr auto; align-items: center;
    gap: 3px 8px;
  }
  .dv2-bar-lbl { font-size: .84rem; font-weight: 800; color: var(--text); }
  .sb-bar-row .sb-bar-nums {
    font-size: .8rem; font-weight: 700; color: var(--text2);
    font-variant-numeric: tabular-nums; text-align: right;
  }
  .sb-bar-row .sb-bar-track { grid-column: 1 / -1; height: 7px; border-radius: 50px; }
  .sb-qs-ap { display: none; }
  .sb-quick-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Vergroessern-Knopf am Chat. Sichtbare Groesse klein, Trefferflaeche 44px. */
  /* Der Chat bringt in seiner Statuszeile ein eigenes Maximieren mit
     (#chatExpandBtn -> toggleChatModal). Zwei Symbole nebeneinander, die
     Aehnliches tun, sind eine Falle - dieses hier bleibt dem Log. */
  .log-sidebar.dv2-zeigt-chat .dv2-chat-gross { display: none; }
  .dv2-chat-gross {
    position: relative; margin-left: auto; margin-right: 4px;
    width: 32px; height: 32px; display: grid; place-items: center;
    border: 0; background: none; cursor: pointer; border-radius: 9px;
    color: var(--text2); transition: background .14s, color .14s;
  }
  .dv2-chat-gross::after {
    content: ''; position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%); width: 44px; height: 44px;
  }
  .dv2-chat-gross:hover { background: var(--bg2); color: var(--text); }
  .dv2-chat-gross .dv2-ico { width: 1rem; height: 1rem; }
  .dv2-chat-gross .dv2-ico:nth-of-type(2),
  .dv2-chat-ist-gross .dv2-chat-gross .dv2-ico:nth-of-type(1) { display: none; }
  .dv2-chat-ist-gross .dv2-chat-gross .dv2-ico:nth-of-type(2) { display: block; }
  .dv2-chat-ist-gross .dv2-chat-gross { background: var(--primary-l); color: var(--dv2-primary-text); }

  .log-sidebar.dv2-chat-ist-gross { width: clamp(560px, 72%, 1100px); max-height: min(58vh, 560px); }
  .log-sidebar.dv2-chat-ist-gross .log-sidebar-body { max-height: min(44vh, 420px); }

  /* Ortsname: steht links oben AUF der Buehne, nicht mehr im Kopf der Spalte
     (dorthin verschoben von dv2OrtAufDieBuehne). Haengt er doch in der Spalte -
     also ausserhalb der Dorfansicht -, bleibt er unsichtbar, damit die Spalte
     oben wirklich leer anfaengt. */
  .sidebar .sb-loc-hdr { display: none; }

  /* ── Kopfecke: Ortsschild und Begrüßung untereinander ──────────────────
     Beides in EINEM absolut gesetzten Kasten. Zwei getrennte absolute
     Positionen müssten sonst auf die Höhe des Schildes abgestimmt werden -
     und die ändert sich mit der Schriftgröße. */
  .dv2-kopfecke {
    position: absolute; left: var(--dv2-luft); top: var(--dv2-luft); z-index: 10;
    display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
    max-width: min(520px, 46%);
    pointer-events: none;
  }
  .dv2-kopfecke > * { pointer-events: auto; }

  .dv2-kopfecke > .sb-loc-hdr {
    position: static; display: flex; align-items: center; margin: 0;
    padding: 8px 15px; border-radius: 14px;
    /* Eigene Flaeche statt blossem Schlagschatten: der Hintergrund reicht vom
       hellen Himmel bis zum dunklen Laub - darueber waere kein Kontrastwert
       verlaesslich zu halten. */
    background: var(--card, rgba(255, 255, 255, .94));
    border: 1px solid var(--border, #e2e8f0);
    box-shadow: 0 4px 16px rgba(28, 44, 74, .16);
    backdrop-filter: blur(7px);
  }
  .dv2-kopfecke > .sb-loc-hdr .sb-loc-icon-name {
    display: flex; align-items: center; gap: 9px;
    font-family: Cinzel, Georgia, serif;
    font-size: clamp(1rem, 1.5cqw, 1.32rem); font-weight: 700;
    letter-spacing: .04em; color: var(--text);
  }
  .dv2-kopfecke > .sb-loc-hdr .sb-loc-icon { font-size: 1.1em; line-height: 1; }

  /* ── Begrüßung ────────────────────────────────────────────────────────
     Wie in Minnis Vorlage: kein Kasten, der Text steht direkt auf der Szene.
     Damit er das auch über dunklem Laub und im Nachtmodus aushält, liegt ein
     weicher heller Schleier darunter statt einer harten Karte. */
  .dv2-willkommen {
    padding: 2px 20px 2px 2px;
    /* Schleier statt Karte: in der Vorlage steht der Text auf hellem Himmel.
       Hier liegt er je nach Bildausschnitt auch ueber dunklem Laub - ohne
       Grundierung war er dort nicht mehr lesbar (nachgemessen). Weicher
       Verlauf plus Unschaerfe: traegt den Kontrast, ohne als Kasten zu wirken. */
    background: radial-gradient(112% 128% at 8% 8%,
      color-mix(in srgb, var(--card) 92%, transparent) 0%,
      color-mix(in srgb, var(--card) 78%, transparent) 46%,
      color-mix(in srgb, var(--card) 30%, transparent) 78%,
      transparent 100%);
    backdrop-filter: blur(6px);
  }
  .dv2-willkommen-titel {
    display: flex; align-items: center; gap: 10px;
    margin: 0 0 6px; padding: 0;
    font-size: clamp(1.05rem, 1.5cqw, 1.32rem); font-weight: 800;
    line-height: 1.25; color: var(--text);
  }
  .dv2-willkommen-icon { font-size: 1.5em; line-height: 1; }
  /* In der Vorlage ist der Fliesstext klar dunkel, nicht grau abgesetzt -
     er soll gelesen werden, nicht nur dastehen. */
  .dv2-willkommen-text {
    margin: 0 0 11px; max-width: 44ch;
    font-size: clamp(.84rem, 1.05cqw, .95rem); font-weight: 500;
    line-height: 1.5; color: var(--text);
  }
  /* Der Ortshinweis ist die einzige Fläche im Block - so wie in der Vorlage. */
  .dv2-willkommen-ort {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 7px 14px 7px 11px; border-radius: 50px;
    font-size: clamp(.78rem, .95cqw, .87rem); font-weight: 600; color: var(--text);
    background: color-mix(in srgb, var(--card) 78%, transparent);
    border: 1px solid var(--border-weich, var(--border));
    backdrop-filter: blur(7px);
  }
  .dv2-willkommen-ort b { font-weight: 800; color: var(--text); }
  .dv2-willkommen-nadel { display: grid; place-items: center; color: var(--text3, var(--text2)); }
  .dv2-willkommen-nadel .dv2-ico { width: 15px; height: 15px; }

  /* 520px breit endet der Block bei 1440px Fenster rund bei 43% der Buehne -
     die Tages-Events beginnen erst bei 73%, die Bewohner stehen tiefer. Erst
     darunter wird es eng; dann faellt der Fliesstext weg, Titel und Ortszeile
     bleiben. */
  @media (max-width: 1100px) {
    .dv2-willkommen-text { display: none; }
  }

  /* Wolkenstreifen als Abschluss der Spalte. */
  .dv2-wolke {
    margin: auto calc(-1 * var(--dv2-luft)) 0; flex: none;
    height: clamp(52px, 6vh, 74px);
    background: no-repeat bottom center / 100% auto
      url('../assets/dorf/wolke.webp');
    opacity: .9; pointer-events: none;
  }
  [data-theme="dark"] .dv2-wolke { opacity: .18; }



  /* ── Begleiter: Bund oder Team ─────────────────────────────────────────
     Der Entwurf zeigt die Bundkarte; das aktive Team ist im Spiel ebenso
     wichtig, deshalb ein Umschalter statt einer Entscheidung. */
  .dv2-comp-reiter { display: flex; gap: 3px; margin: 2px 0 9px; }
  .dv2-comp-reiter button {
    flex: 1; min-height: 30px; padding: 0 8px; border: 0; border-radius: 8px;
    cursor: pointer; font: inherit; font-size: .76rem; font-weight: 800;
    color: var(--text2); background: var(--bg2); transition: .14s;
  }
  .dv2-comp-reiter button:hover { color: var(--text); }
  .dv2-comp-reiter button.ist-aktiv { color: var(--dv2-primary-text); background: var(--primary-l); }
  /* Ohne Seelenbund: „Bund" ausgegraut, nicht klickbar (Hinweis im title). */
  .dv2-comp-reiter button:disabled { cursor: not-allowed; opacity: .45; }
  .dv2-comp-reiter button:disabled:hover { color: var(--text2); }
  /* Kein Knopf „Begleiter" mehr — Kacheln und Bundkarte fuehren selbst hin. */
  .sb-companions #sbComps .sb-comp-avatar { cursor: pointer; }
  .sb-companions #sbComps .sb-comp-avatar.empty:hover { opacity: .6; }
  .dv2-comp-bund:has(.dv2-comp-zeile) { cursor: pointer; border-radius: 12px; }
  .dv2-comp-bund:has(.dv2-comp-zeile):hover .dv2-comp-bild { border-color: var(--primary); }

  /* Entweder Bund ODER Team — seit dem Schnellzugriff ist der Platz knapp.
     ⚠️ #sbComps im Selektor ist Absicht: style.css setzt `#sbComps{display:grid}`, und
     eine ID schlaegt jede Klassenkette. Mit nur `.sb-comp-grid` blieb das Team seit
     4be638b IMMER stehen, auch unter „Bund". Regression 162 rechnet die Spezifitaet nach. */
  .sb-companions.dv2-zeigt-team .dv2-comp-bund { display: none; }
  .sb-companions:not(.dv2-zeigt-team) #sbComps { display: none; }

  .dv2-comp-zeile { display: flex; align-items: flex-start; gap: 11px; }
  .dv2-comp-bild {
    width: 58px; height: 58px; flex: none; border-radius: 13px; overflow: hidden;
    display: grid; place-items: center; font-size: 1.6rem;
    background: var(--primary-l); border: 1px solid var(--border);
  }
  .dv2-comp-bild img { width: 100%; height: 100%; object-fit: cover; }
  .dv2-comp-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
  .dv2-comp-text b { font-size: 1.02rem; font-weight: 800; line-height: 1.15; }
  .dv2-comp-text small { font-size: .78rem; font-weight: 700; color: var(--text2); }
  .dv2-comp-xp {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    margin-top: 3px; font-size: .72rem; font-weight: 700; color: var(--text2);
    font-variant-numeric: tabular-nums;
  }
  .dv2-comp-track {
    display: block; height: 6px; border-radius: 50px; overflow: hidden;
    background: var(--bg2); margin-top: 2px;
  }
  .dv2-comp-track i { display: block; height: 100%; border-radius: 50px;
    background: linear-gradient(90deg, var(--green), #6fd0a0); }
  .dv2-comp-leer { margin: 0; font-size: .78rem; font-weight: 600; color: var(--text2); }

  /* ── Profilmenü mit Reitern ────────────────────────────────────────────
     Nach Minnis Entwurf. Aufbau: Kopf, Reiterleiste, ein Blatt je Reiter,
     fester Fuß mit Abmelden und den Pflichtangaben. */
  /* hidden muss hier IMMER gewinnen: mehrere Regeln in diesem Block setzen
     display (inline-flex, grid, flex) und schlagen sonst das Attribut - die
     Online-Marke und die alte Unterzeile blieben dadurch sichtbar. */
  #topnavDropdown [hidden] { display: none !important; }

  #topnavDropdown {
    width: min(430px, calc(100vw - 24px));
    padding: 0; overflow: hidden;
    border-radius: 18px;
  }

  /* Kopf */
  .dv2-dd-kopf {
    display: flex; align-items: center; gap: 13px;
    padding: 15px 16px 13px;
  }
  /* Naeher heran als in der Spalte: hier soll der Kopf zu sehen sein, nicht
     die ganze Figur. Die Werte passen zu den Charaktergrafiken, bei denen der
     Kopf im oberen Fuenftel sitzt. */
  .dv2-dd-bild {
    flex: none; width: 52px; height: 52px; border-radius: 50%;
    background-color: var(--primary-l);
    background-repeat: no-repeat;
    background-size: 245%;
    background-position: 50% 7%;
    box-shadow: 0 0 0 2px var(--card), 0 0 0 3.5px var(--primary);
  }
  .dv2-dd-wer { display: flex; flex-direction: column; min-width: 0; flex: 1; }
  .dv2-dd-wer #topnavDdName {
    font-size: 1.12rem; font-weight: 800; color: var(--text); line-height: 1.25;
  }
  .dv2-dd-rolle { font-size: .82rem; font-weight: 600; color: var(--text2); }
  .dv2-dd-online {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 11px; border-radius: 50px;
    font-size: .76rem; font-weight: 700;
    color: #15803d; background: #dcfce7;
  }
  .dv2-dd-online i { width: 7px; height: 7px; border-radius: 50%; background: #22c55e; }
  [data-theme="dark"] .dv2-dd-online { color: #86efac; background: rgba(34,197,94,.16); }

  /* Reiterleiste */
  .dv2-dd-reiter {
    display: grid; grid-template-columns: repeat(4, 1fr);
    border-top: 1px solid var(--border-weich, var(--border));
    border-bottom: 1px solid var(--border-weich, var(--border));
  }
  .dv2-dd-reiter button {
    display: flex; flex-direction: column; align-items: center; gap: 5px;
    padding: 10px 4px 9px; border: 0; background: none; cursor: pointer;
    font-size: .76rem; font-weight: 700; color: var(--text2);
    border-bottom: 2.5px solid transparent;
    transition: background .14s, color .14s;
  }
  .dv2-dd-reiter button:hover { background: var(--bg2, rgba(0,0,0,.04)); color: var(--text); }
  .dv2-dd-reiter button.ist-aktiv {
    color: var(--dv2-primary-text); background: var(--primary-l, rgba(79,110,247,.1));
    border-bottom-color: var(--primary);
  }
  .dv2-dd-reiter-icon { display: grid; place-items: center; }
  /* Reiter mit Ungelesenem: derselbe rote Punkt wie am Profilknopf, am Symbol. */
  .dv2-dd-reiter button.hat-neues .dv2-dd-reiter-icon { position: relative; }
  .dv2-dd-reiter button.hat-neues .dv2-dd-reiter-icon::after {
    content: ''; position: absolute; top: -2px; right: -5px;
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--red); box-shadow: 0 0 0 2px var(--card);
  }
  .dv2-dd-reiter .dv2-ico { width: 20px; height: 20px; }

  /* Blätter */
  .dv2-dd-blatt { padding: 13px 12px 6px; }
  .dv2-dd-blatt[hidden] { display: none; }
  .dv2-dd-gruppe-titel {
    margin: 0 0 8px; padding: 0 6px;
    font-size: .7rem; font-weight: 800; letter-spacing: .05em;
    text-transform: uppercase; color: var(--text2);
  }

  /* Zeilen */
  #topnavDropdown .dv2-dd-item {
    display: flex; align-items: center; gap: 12px; width: 100%;
    min-height: 56px; padding: 8px 8px; margin: 0;
    border: 0; border-radius: 12px; background: none;
    text-align: left; cursor: pointer; transition: background .14s;
  }
  #topnavDropdown .dv2-dd-item + .dv2-dd-item {
    border-top: 1px solid var(--border-weich, var(--border));
    border-radius: 0;
  }
  #topnavDropdown .dv2-dd-item:hover { background: var(--bg2, rgba(0,0,0,.04)); }
  .dv2-dd-icon {
    flex: none; display: grid; place-items: center;
    width: 40px; height: 40px; border-radius: 11px;
    color: var(--dv2-primary-text); background: var(--primary-l, rgba(79,110,247,.12));
  }
  .dv2-dd-icon .dv2-ico { width: 20px; height: 20px; }
  .dv2-dd-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
  .dv2-dd-text b { font-size: .9rem; font-weight: 800; color: var(--text); }
  .dv2-dd-text small { font-size: .77rem; font-weight: 600; color: var(--text2); line-height: 1.3; }
  /* Rot wie der Punkt am Profilknopf und am Reiter „Soziales" — die drei
     gehoeren zusammen, und nur in derselben Farbe liest man sie als Kette. */
  .dv2-dd-marke {
    flex: none; min-width: 26px; height: 26px; padding: 0 8px;
    display: grid; place-items: center; border-radius: 50px;
    font-size: .76rem; font-weight: 800;
    color: #fff; background: var(--red);
  }
  .dv2-dd-marke[hidden] { display: none; }
  .dv2-dd-pfeil { flex: none; display: grid; place-items: center; color: var(--text3, var(--text2)); }
  .dv2-dd-pfeil .dv2-ico { width: 17px; height: 17px; }
  /* Das Chevron zeigt nach unten und wird nach rechts gedreht. Der externe
     Pfeil zeigt schon aus dem Spiel heraus - der bleibt, wie er ist. */
  .dv2-dd-pfeil:not(.ist-extern) .dv2-ico { transform: rotate(-90deg); }

  /* Fuß */
  .dv2-dd-fuss { padding: 6px 12px 10px; border-top: 1px solid var(--border-weich, var(--border)); }
  #topnavDropdown .dv2-dd-schluss {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 100%; min-height: 46px; margin: 6px 0 0; padding: 0 14px;
    border-radius: 12px; cursor: pointer;
    font-size: .92rem; font-weight: 800;
    border: 1px solid var(--border-weich, var(--border));
    background: var(--bg-panel-2, rgba(0,0,0,.03)); color: var(--text);
    transition: background .14s, border-color .14s;
  }
  #topnavDropdown .dv2-dd-schluss .dv2-dd-icon {
    width: 26px; height: 26px; border-radius: 8px; background: none;
  }
  #topnavDropdown .dv2-dd-schluss .dv2-ico { width: 19px; height: 19px; }
  /* Abmelden steht abgesetzt: es soll nicht im Vorbeigehen getroffen werden. */
  #topnavDropdown .dv2-dd-schluss.ist-warn {
    color: var(--dv2-warn-fest); background: var(--rot-soft, #fef2f2);
    border-color: color-mix(in srgb, var(--dv2-warn-fest) 26%, transparent);
  }
  #topnavDropdown .dv2-dd-schluss.ist-warn .dv2-dd-icon { color: var(--dv2-warn-fest); }
  #topnavDropdown .dv2-dd-schluss.ist-warn:hover {
    border-color: var(--dv2-warn-fest);
  }
  [data-theme="dark"] #topnavDropdown .dv2-dd-schluss.ist-warn {
    color: #fca5a5; background: rgba(220,38,38,.14);
  }
  [data-theme="dark"] #topnavDropdown .dv2-dd-schluss.ist-warn .dv2-dd-icon { color: #fca5a5; }

  .dv2-dd-recht {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    margin-top: 9px; padding-top: 9px;
    border-top: 1px solid var(--border-weich, var(--border));
    font-size: .76rem; color: var(--text2);
  }
  #topnavDropdown .dv2-dd-recht-link {
    display: inline; padding: 2px 3px; border: 0; background: none;
    font-size: .76rem; font-weight: 600; color: var(--text2);
    text-decoration: underline; cursor: pointer;
  }
  #topnavDropdown .dv2-dd-recht-link:hover { color: var(--dv2-primary-text); }

  /* Sammelpunkt: die Einzel-Icons sind aus der Leiste verschwunden, offene
     Post oder Anfragen muessen trotzdem auffallen. */
  #topnavProfileBtn { position: relative; }
  #topnavProfileBtn.dv2-hat-neues::after {
    content: ''; position: absolute; top: 2px; right: 2px;
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--red); box-shadow: 0 0 0 2px var(--card);
  }

  /* Diese Ziele stehen jetzt im Profilmenü - die Leiste bleibt schmal. */
  #reloadBtn, #mailBtn, #friendsBtn, #leaderboardBtn,
  .topnav-icon-btn[onclick*="openFeedbackModal"] { display: none !important; }

  /* Angriff und Verteidigung stehen auf der Charakterseite. */
  .sb-quick-stats { display: none !important; }

  /* ── Megamenü ──────────────────────────────────────────────────────────
     Ein Panel fuer alle vier Menues, haengt unter seinem Knopf. Die
     Ausrichtung setzt JS (siehe dv2MegaAusrichten). */
  .dv2-mega {
    display: none; position: absolute; top: calc(100% + 6px); left: var(--dv2-luft);
    z-index: 120; width: min(680px, calc(100vw - 28px));
    padding: 17px 19px 19px; overflow: hidden;
    background: var(--card, #fff); border: 1px solid var(--border, #e2e8f0);
    border-radius: 20px; box-shadow: 0 14px 40px rgba(28,44,74,.18);
  }
  .dv2-mega.ist-offen { display: block; animation: dv2MegaAuf .18s ease-out; }
  @keyframes dv2MegaAuf { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

  /* Zweig als Ecke. Feste Hoehe mit object-fit:cover BESCHNEIDET ihn, statt
     ihn zu stauchen — so bleibt er im Kopfbereich und nie ueber dem Text
     der Menuepunkte. */
  .dv2-mega-deko {
    position: absolute; top: -16px; right: -20px;
    width: clamp(118px, 13vw, 158px); height: 96px;
    object-fit: cover; object-position: right top;
    opacity: .38; transform: scaleX(-1); pointer-events: none; user-select: none;
  }
  [data-theme="dark"] .dv2-mega-deko { opacity: .2; }

  /* Der Inhalt liegt ueber der Deko. */
  .dv2-mega-kopf, .dv2-mega-liste { position: relative; z-index: 1; }
  .dv2-mega-kopf { margin-bottom: 13px; padding-right: clamp(104px, 13vw, 142px); min-height: 64px; }
  .dv2-mega-titel { margin: 0; font-size: 1.18rem; font-weight: 800; line-height: 1.2; color: var(--text); }
  .dv2-mega-spruch { margin: 3px 0 0; font-size: .83rem; font-weight: 600; color: var(--text2); }

  .dv2-mega-liste { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 5px; }
  .dv2-mega-punkt {
    position: relative; display: flex; align-items: flex-start; gap: 11px;
    min-height: 56px; padding: 9px 11px; border: 0; background: none;
    border-radius: 13px; cursor: pointer; text-align: left; font: inherit;
    transition: background .14s;
  }
  .dv2-mega-punkt:hover { background: var(--primary-l, rgba(79,110,247,.1)); }
  .dv2-mega-punkt:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
  .dv2-mega-icon {
    display: grid; place-items: center; flex-shrink: 0; width: 34px; height: 34px;
    border-radius: 10px; color: var(--dv2-primary-text);
    background: var(--primary-l, rgba(79,110,247,.12)); transition: .14s;
  }
  .dv2-mega-icon .dv2-ico { width: 1.08rem; height: 1.08rem; }
  .dv2-mega-punkt:hover .dv2-mega-icon { background: var(--dv2-auf-weiss); color: #fff; }
  .dv2-mega-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .dv2-mega-text b { font-size: .9rem; font-weight: 800; color: var(--text); }
  .dv2-mega-text small { font-size: .76rem; font-weight: 600; color: var(--text2); line-height: 1.35; }
  .dv2-mega-badge {
    position: absolute; top: 9px; right: 10px;
    min-width: 18px; height: 18px; padding: 0 5px; border-radius: 50px;
    display: grid; place-items: center;
    font-size: .68rem; font-weight: 900; color: #fff; background: var(--dv2-warn-fest);
  }

  /* ── Dorfszene ─────────────────────────────────────────────────────────
     Randloses Bild, Figuren stehen frei darauf. Ersetzt Banner und
     Portraitstreifen; beide bleiben im DOM, weil die Szene ihre
     Beschriftungen daraus liest. */
  /* Ob die Buehne ueberhaupt gebaut wird, entscheidet _dv2Buehne() im JS -
     siehe Begruendung dort. Hier reicht die Versteckregel. */
  .dv2-versteckt { display: none !important; }

  /* Die Szene ist die Buehne: sie sitzt fest oben in der Spalte, der uebrige
     Dorfinhalt scrollt darunter. Deshalb liegt sie NEBEN .content-scroll und
     nicht darin - sonst wuerde sie mitscrollen und der Chat mit ihr.

     background-position "center bottom" ist entscheidend: bei "cover" schneidet
     ein breiter Rahmen oben UND unten ab (gemessen 156px je Seite). Ohne diese
     Zeile fehlt der Bildboden und die Figuren schweben in der Luft. */
  .dv2-szene {
    position: relative; flex: 1 1 auto;
    width: 100%; min-height: var(--dv2-szene-h);
    overflow: hidden; isolation: isolate;
    background: url('../assets/dorf/szene.webp') center bottom / cover no-repeat;
    /* Bezugsrahmen fuer die Figurengroesse (cqw = Prozent der Buehnenbreite). */
    container-type: size;
  }
  .main-col { flex-direction: column; }
  /* Es gibt nur ein Tagbild. Der Nachtmodus graded es, statt ein zweites zu
     laden: abdunkeln und kuehl ueberlagern, unten waermer wegen der Fenster. */
  [data-theme="dark"] .dv2-szene::after {
    content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background:
      radial-gradient(90% 55% at 52% 88%, rgba(120,78,32,.20), transparent 70%),
      linear-gradient(180deg, rgba(12,28,60,.60) 0%, rgba(8,18,40,.48) 46%, rgba(5,12,28,.40) 100%);
  }

  /* ── Bewohnerreihe ─────────────────────────────────────────────────────
     Waagerechte Reihe runder Marken statt handgesetzter Freisteller. Ring und
     Rollenanhaenger stecken im Bild (assets/npc/*-dot.webp).

     Senkrechte Lage: siehe .dv2-fuss - Reihe und Chat stehen in einem
     Stapel, die Reihe kann also gar nicht unter dem Chat landen. */
  /* Fussstapel: Reihe oben, Chat darunter. Beide liegen damit zwangslaeufig
     richtig zueinander - egal wie hoch der Chat gerade ist, und ohne dass
     irgendetwas gemessen wird.
     pointer-events:none, weil der Stapel die volle Breite einnimmt und sonst
     den Wegweiser rechts unten unklickbar machte. */
  .dv2-fuss {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 40;
    display: flex; flex-direction: column; align-items: flex-start;
    gap: 13px; padding-bottom: var(--dv2-luft);
    pointer-events: none;
  }
  .dv2-fuss > * { pointer-events: auto; }
  /* AUSSER der Reihe: ihr rechtes Polster liegt ueber dem Wegweiser und
     verschluckte dort die Klicks - gemessen die oberen 87px seiner Hoehe.
     Das Schild ist also nicht zu klein, es war verdeckt. Klicks nehmen nur
     die Spur und die Pfeile an. */
  .dv2-fuss > .dv2-reihe { pointer-events: none; }
  .dv2-reihe-spur, .dv2-reihe-pfeil { pointer-events: auto; }

  .dv2-reihe {
    align-self: stretch;
    display: flex; align-items: center; gap: 6px;
    padding-left: var(--dv2-luft);
    /* Rechts steht der Wegweiser. Fester Platz reicht: er hat feste Groesse
       und sitzt immer unten rechts. Die Tages-Events oben rechts liegen nie
       auf dieser Hoehe und brauchen deshalb keinen. */
    padding-right: calc(var(--dv2-luft) * 2 + clamp(150px, 16vw, 210px));
  }
  .dv2-reihe-spur {
    flex: 1 1 auto; min-width: 0;
    display: flex; align-items: flex-end; justify-content: center;
    gap: clamp(6px, 1.4cqw, 22px);
    /* Oben Platz fuer Namensschild und Marke, unten fuer den Hover-Sprung.
       Die Spur MUSS oben so viel Luft haben wie das Schild hoch ist: sie
       scrollt waagerecht, und overflow-x:auto zwingt overflow-y auf hidden -
       was ueber den Rand ragt, wird abgeschnitten. */
    padding: 64px 4px 10px;
    overflow-x: auto; overflow-y: hidden;
    scroll-behavior: smooth; scrollbar-width: none;
  }
  .dv2-reihe-spur::-webkit-scrollbar { display: none; }
  /* Bei Ueberhang linksbuendig: zentriert waere die erste Marke angeschnitten
     und liesse sich nicht mehr ganz nach rechts scrollen. */
  .dv2-reihe.hat-pfeile .dv2-reihe-spur { justify-content: flex-start; }

  .dv2-kreis {
    position: relative; flex: 0 0 auto;
    border: 0; background: none; padding: 0; cursor: pointer; line-height: 0;
    /* An der Buehnenbreite gemessen (cqw). Groesser als der erste Entwurf:
       mit 7.6cqw wirkten sechs Marken auf breiter Buehne verloren. */
    width: clamp(78px, 9.4cqw, 124px);
    transition: transform .18s;
  }
  .dv2-kreis img {
    width: 100%; height: auto; display: block;
    filter: drop-shadow(0 8px 14px rgba(28, 44, 34, .38));
  }
  .dv2-kreis:hover { transform: translateY(-6px); z-index: 5; }
  .dv2-kreis:focus-visible { outline: 3px solid var(--primary); outline-offset: 4px; border-radius: 50%; }
  .dv2-kreis.ist-fort { filter: grayscale(.75) opacity(.62); cursor: default; }
  .dv2-kreis.ist-fort:hover { transform: none; }

  /* Ersatz fuer Bewohner ohne eigenes Kreisbild (z.B. Wilma): das Portrait aus
     dem Streifen rund beschnitten, mit demselben Goldrand. */
  .dv2-kreis-ersatz {
    display: block; width: 100%; aspect-ratio: 1; border-radius: 50%;
    overflow: hidden; background: var(--bg-panel-2, #eef2f7);
    box-shadow: 0 0 0 3px #d9b45e, 0 8px 14px rgba(28, 44, 34, .38);
  }
  .dv2-kreis-ersatz img { width: 100%; height: 100%; object-fit: cover; filter: none; }

  .dv2-kreis-marke { position: absolute; top: 0; right: -2px; z-index: 4; }
  /* Das Abzeichen kommt aus dem Bestandsmarkup und bringt seine Farben mit. */
  .dv2-kreis-marke .tnpc-notify-badge { position: static; animation: none; }

  /* Der Name erscheint beim Zeigen oder per Tastatur. Dauerhaft sichtbar
     waeren sechs Schilder mehr Text als Bild - der Rollenanhaenger im Kreis
     sagt bereits, um wen es geht. Fuer Screenreader steht alles im
     aria-label, das Schild ist reine Sehhilfe. */
  .dv2-kreis-schild {
    /* UEBER der Marke: unter ihr wurde es von der scrollenden Spur
       angeschnitten (gemessen 27px). */
    position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%);
    z-index: 6; display: flex; flex-direction: column; line-height: 1.2;
    padding: 5px 11px; border-radius: 11px; white-space: nowrap;
    background: var(--card, rgba(255, 255, 255, .94));
    border: 1px solid var(--border, #e2e8f0);
    box-shadow: 0 2px 10px rgba(38, 53, 74, .14);
    opacity: 0; pointer-events: none; transition: opacity .14s;
  }
  .dv2-kreis:hover .dv2-kreis-schild,
  .dv2-kreis:focus-visible .dv2-kreis-schild { opacity: 1; }
  .dv2-kreis-schild b { font-size: .8rem; font-weight: 800; color: var(--text); }
  .dv2-kreis-schild small { font-size: .7rem; font-weight: 700; color: var(--text2); }

  /* Pfeile stehen nur da, wenn die Reihe wirklich ueberhaengt - die Klasse
     setzt dv2ReihePfeile(). 44px, damit sie auf Touch treffbar bleiben. */
  .dv2-reihe-pfeil {
    flex: 0 0 auto; display: none; place-items: center;
    width: 44px; height: 44px; border-radius: 50%;
    border: 1px solid var(--border, #e2e8f0);
    background: var(--card, #fff); color: var(--text);
    box-shadow: 0 4px 14px rgba(28, 44, 74, .20); cursor: pointer;
    transition: background .14s, opacity .14s;
  }
  .dv2-reihe.hat-pfeile .dv2-reihe-pfeil { display: grid; }
  .dv2-reihe-pfeil:hover:not(:disabled) { background: var(--bg-panel-2, #f1f5f9); }
  .dv2-reihe-pfeil:disabled { opacity: .35; cursor: default; }
  .dv2-reihe-pfeil .dv2-ico { width: 20px; height: 20px; }
  /* Ein Chevron-Pfad fuer beide Seiten - gedreht statt zweimal gezeichnet. */
  .dv2-reihe-pfeil.ist-links  .dv2-ico { transform: rotate(90deg); }
  .dv2-reihe-pfeil.ist-rechts .dv2-ico { transform: rotate(-90deg); }

  /* Wegweiser als Einstieg in den Wald. Text und Knopf sind HTML, nicht ins
     Bild gebrannt — damit sie uebersetzbar bleiben. */
  .dv2-wegweiser {
    position: absolute; right: var(--dv2-luft); bottom: var(--dv2-luft); z-index: 10;
    width: clamp(150px, 16vw, 210px); display: grid; place-items: center;
    border: 0; background: none; padding: 0; cursor: pointer;
    filter: drop-shadow(0 12px 18px rgba(28,44,34,.32));
  }
  .dv2-wegweiser img { grid-area: 1/1; width: 100%; height: auto; }
  /* Das Schildholz ist gescheckt: helle Maserung neben fast schwarzen Fugen.
     Die Platte dunkelt es ab, statt es zu verdecken. */
  .dv2-wegweiser-text {
    grid-area: 1/1; align-self: start; justify-self: center;
    margin-top: 12%; width: 80%; padding: 6px 10px 8px;
    text-align: center; border-radius: 12px;
    font-size: clamp(.92rem, 1.15vw, 1.3rem); font-weight: 800; line-height: 1.15; color: #fff;
    -webkit-backdrop-filter: brightness(.45) saturate(1.15);
    backdrop-filter: brightness(.45) saturate(1.15);
    text-shadow: 0 2px 5px rgba(20,12,4,.85);
  }
  @supports not (backdrop-filter: brightness(.45)) {
    .dv2-wegweiser-text { background: rgba(38,24,10,.68); }
  }
  .dv2-wegweiser-knopf {
    grid-area: 1/1; align-self: start; justify-self: center; margin-top: 50%;
    display: inline-flex; align-items: center; gap: 7px;
    min-height: 40px; padding: 0 15px; border-radius: 50px;
    font-size: .84rem; font-weight: 800; color: #fff;
    background: var(--dv2-auf-weiss); box-shadow: 0 4px 14px rgba(28,44,74,.3);
  }
  .dv2-wegweiser:hover .dv2-wegweiser-knopf { filter: brightness(1.12); }
  .dv2-wegweiser .dv2-ico { width: .95em; height: .95em; }


  /* ── Log und Chat nach unten ───────────────────────────────────────────
     Bisher eine Spalte rechts. Jetzt schwebt die Leiste unten links ueber
     der Szene — wie im Entwurf. Die Logik bleibt unangetastet: Reiter,
     Einklappen und Chateingabe sind dieselben Bausteine, nur anders
     platziert. */
  .main-col { position: relative; }

  /* ── Emote-Auswahl ─────────────────────────────────────────────────────
     Raster mit fester Zeilenzahl statt Umbruch mit Scrollbalken. Die
     Spaltenzahl setzt dv2EmotesZeichnen() aus der gemessenen Breite - so
     haengt nie eine halbe Spalte ueber den Rand und keine Reihe wird
     angeschnitten. */
  .chat-emote-picker {
    display: grid; flex-wrap: nowrap;
    grid-template-columns: repeat(var(--dv2-emote-spalten, 6), 1fr);
    gap: 4px; padding: 10px 12px 6px;
    max-height: none; overflow: visible;
  }
  .chat-emote-picker .chat-emote-pick-btn[hidden] { display: none; }
  .chat-emote-picker .chat-emote-pick-btn { display: grid; place-items: center; }
  .chat-emote-picker .chat-emote-pick-btn img { width: 46px; height: 46px; }
  /* In der kleinen Ansicht kleiner: der Popover schwebt ueber dem Verlauf,
     jede Zeile weniger ist dort ein Stueck lesbarer Chat mehr. */
  .ls-chat-body:not(.chat-modal-mode) .chat-emote-picker .chat-emote-pick-btn img {
    width: 38px; height: 38px;
  }

  .dv2-emote-pager {
    grid-column: 1 / -1;
    display: flex; align-items: center; justify-content: center; gap: 12px;
    padding-top: 4px; margin-top: 2px;
    border-top: 1px solid var(--border-weich, var(--border));
  }
  .dv2-emote-stand { font-size: .74rem; font-weight: 700; color: var(--text2); }
  .dv2-emote-pfeil {
    display: grid; place-items: center; width: 28px; height: 28px;
    border: 0; border-radius: 8px; background: none; color: var(--text2);
    cursor: pointer; transition: background .14s, opacity .14s;
  }
  .dv2-emote-pfeil:hover:not(:disabled) { background: var(--bg2, rgba(0,0,0,.05)); color: var(--text); }
  .dv2-emote-pfeil:disabled { opacity: .3; cursor: default; }
  .dv2-emote-pfeil .dv2-ico { width: 16px; height: 16px; transform: rotate(90deg); }
  .dv2-emote-pfeil.ist-rechts .dv2-ico { transform: rotate(-90deg); }

  /* ── Charakterköpfe in runden Feldern ─────────────────────────────────
     Die Charaktergrafiken sind Ganzkoerperbilder (214x432). Um den KOPF zu
     zeigen, wird das Bild vergroessert und oben ausgerichtet - der Kreis
     schneidet den Rest ab. Der Buchstabe bleibt darunter stehen und kommt
     zurueck, falls eine Ebene nicht laedt. */
  /* Zoom und Versatz kommen je Rasse aus DV2_KOPFMASS (dorf-v2.js) und sind
     am Alphakanal der Grundfiguren GEMESSEN. Ein gemeinsamer Wert ging nicht:
     die Figur beginnt beim Ork bei y=58, beim Zwerg erst bei y=136.
     Beides prozentual, gilt damit fuer die 22px-Chatmarke wie fuer den
     52px-Kreis im Profilmenue. */
  .dv2-kopf-ebene {
    position: absolute; left: 50%; top: var(--dv2-kopf-oben, -80%);
    width: var(--dv2-kopf-breite, 190%); height: auto;
    transform: translateX(-50%);
    pointer-events: none;
  }
  /* Sobald ein Kopf steht, verschwindet der Buchstabe. */
  .dv2-hat-kopf { font-size: 0 !important; position: relative; overflow: hidden; }

  /* Chatmarken tragen die Ebenen. */
  .ls-chat-body .chat-bubble-avatar { position: relative; overflow: hidden; }

  /* Kopfbild im Profilmenue: gleiche Ebenen, nur groesser. */
  .dv2-dd-bild { position: relative; overflow: hidden; }
  .dv2-dd-bild.dv2-hat-kopf { background-image: none !important; }

  /* Chat und Log gehoeren auf den Dorfplatz. Ausserhalb bleibt der Kasten im
     DOM (die Chatverbindung laeuft weiter), wird aber nicht angezeigt. Die
     Markierung setzt renderTown(), siehe dv2DorfplatzMarkieren. */
  .main-col:not(.dv2-ist-dorfplatz) #logSidebar { display: none; }

  /* Das Logo fuehrt auf den Dorfplatz. */
  .topnav-logo { cursor: pointer; }
  .topnav-logo:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 8px; }

  /* Der Chat haengt im Fussstapel (siehe dv2ChatInDenStapel), steht dort
     also im Fluss statt frei positioniert. Die Reihe darueber rueckt dadurch
     automatisch mit, wenn er waechst oder eingeklappt wird. */
  .log-sidebar {
    position: relative; left: auto; right: auto; top: auto; bottom: auto;
    margin-left: var(--dv2-luft);
    z-index: 40; width: clamp(380px, 52%, 720px); height: auto;
    max-height: min(30vh, 280px);
    border: 1px solid var(--border); border-radius: 18px;
    box-shadow: 0 12px 34px rgba(28,44,74,.18);
    background: var(--card);
    overflow: hidden;
  }
  /* Eingeklappt: eine schmale Leiste mit den beiden Reitern links und dem
     Pfeil zum Aufklappen rechts.
     style.css blendet .ls-tabs und .ls-hdr-end beim Einklappen aus und zeigt
     stattdessen die senkrechte Lasche - das war fuer den 32px-Streifen am
     rechten Fensterrand gedacht. Unten auf der Buehne ergibt das keinen Sinn,
     deshalb hier beides zurueckgeholt. */
  .log-sidebar.collapsed { max-height: none; height: auto; width: auto; }
  .log-sidebar.collapsed .log-sidebar-body,
  .log-sidebar.collapsed .chat-input-row { display: none !important; }
  .log-sidebar.collapsed .ls-tabs,
  .log-sidebar.collapsed .ls-hdr-end { opacity: 1; pointer-events: auto; }
  .log-sidebar.collapsed .log-sidebar-hdr {
    padding: 2px 6px 2px 10px; gap: 18px; justify-content: space-between;
  }
  /* Leeren und Vergroessern gehoeren zum offenen Log - eingeklappt waeren sie
     nur Beiwerk und machten die Leiste unnoetig breit. */
  .log-sidebar.collapsed .log-clear-hdr,
  .log-sidebar.collapsed .dv2-chat-gross { display: none; }

  /* Der Pfeil muss am unteren Rand nach oben/unten zeigen, nicht nach
     links/rechts.
     Nicht per Drehung: ui.js setzt die Glyphe (◀/▶) bei JEDEM Umschalten neu,
     und style.css unterbindet jede Drehung mit
     ".log-sidebar-toggle{transform:none!important}" - beides fuer die alte
     Lasche am rechten Fensterrand. Statt dagegen anzuschreiben wird die
     Glyphe ausgeblendet und der Pfeil hier gezeichnet. Das !important trifft
     den Knopf, nicht sein ::before - der darf sich also drehen. */
  .log-sidebar .log-sidebar-toggle { font-size: 0; border: 0; background: none; }
  .log-sidebar .log-sidebar-toggle::before {
    content: ""; width: 8px; height: 8px; margin-top: -3px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); transition: transform .16s;
  }
  .log-sidebar.collapsed .log-sidebar-toggle::before {
    margin-top: 3px; transform: rotate(-135deg);
  }
  .log-sidebar .log-sidebar-toggle:hover { background: var(--bg2, rgba(0,0,0,.05)); }

  /* Der Deckel gilt nur fuer den LOG. Auf den Chat angewandt blieben von den
     Nachrichten 123px sichtbar - keine drei Zeilen. Das Modal setzt ohnehin
     seine eigene Hoehe. */
  #lsLogPane { max-height: min(22vh, 200px); }
  /* Solange der Chat offen ist, darf der Kasten hoeher werden - sonst passen
     die im Entwurf geforderten vier bis sechs Nachrichten nicht hinein.
     Die Bewohnerreihe darueber rueckt automatisch mit (siehe .dv2-fuss). */
  .log-sidebar.dv2-zeigt-chat { max-height: min(46vh, 400px); }

  /* Der aufklappbare Streifen am Rand ergibt unten keinen Sinn mehr. */
  .log-sidebar-tab { display: none !important; }

  /* Ohne die Spalte rechts bekommt der Inhalt die volle Breite. */
  .content-scroll { width: 100%; }
  /* In der Dorfansicht ist alles darin versteckt - dann darf es auch keinen
     Platz mehr beanspruchen, sonst bleibt unter der Buehne eine leere Flaeche. */
  .main-col.dv2-hat-szene > .content-scroll { flex: 0 0 auto; padding: 0; }


  /* ── Schwebende Widgets ────────────────────────────────────────────────
     Wie im Entwurf: die Tages-Events liegen rechts oben AUF der Buehne, nicht
     als Block darunter. Das Panel wird dorthin verschoben (siehe
     dv2WidgetsAufDieBuehne), damit Kalenderleiste und Eventliste ihre
     vorhandene Logik behalten. */
  .dv2-widgets {
    position: absolute; right: var(--dv2-luft); top: var(--dv2-luft); z-index: 10;
    /* Breiter als frueher: der Newskasten traegt Text UND Bild nebeneinander.
       Die Tagesliste darunter bleibt trotzdem schmal (siehe unten). */
    width: clamp(360px, 32%, 500px);
    max-height: calc(100% - 2 * var(--dv2-luft));
    display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
    overflow-y: auto; scrollbar-width: thin;
  }
  .dv2-widgets .town-events-panel {
    width: min(100%, 320px); margin: 0; flex: none;
    border-radius: 18px; box-shadow: 0 12px 34px rgba(28,44,74,.18);
  }
  /* Die Wochenleiste IST der Kalender - der liegt jetzt im Fenster. „Alle"
     im Kopf zeigte dorthin und waere neben dem neuen Verweis doppelt. */
  .town-events-panel.dv2-ohne-kalender .town-date-strip,
  .town-events-panel.dv2-ohne-kalender .town-events-see-all { display: none; }

  /* ── Newskasten ────────────────────────────────────────────────────────
     Form, Rand und die Stufe oben rechts stecken im Bild - deshalb kein
     border und kein border-radius hier, sondern 100% 100%: der Kasten waechst
     mit seinem Inhalt, und die Zeichnung waechst mit. */
  .dv2-news {
    position: relative; width: 100%; min-height: 176px;
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px;
    /* ⚠️ Oben/unten bewusst grosszuegig: dieser Abstand IST die Strecke, auf der
       der Schleier auslaufen kann. Mit den fruheren 15/12 px blieben nur 11 px,
       und auf 11 px ist jeder Deckkraftsprung als Kante sichtbar. */
    padding: 28px 16px 24px;
    background: url("../assets/dorf/news-hintergrund-hell.webp") 0 0 / 100% 100% no-repeat;
    filter: drop-shadow(0 12px 26px rgba(28,44,74,.20));
  }
  .dv2-news.hat-bild { grid-template-columns: minmax(0, 1fr) 30%; }
  [data-theme="dark"] .dv2-news {
    background-image: url("../assets/dorf/news-hintergrund-dunkel.webp");
    filter: drop-shadow(0 12px 26px rgba(0,0,0,.38));
  }

  /* EIN Blatt an der unteren linken Ecke - da stoert es nichts. Zwei weitere
     (oben rechts, linke Flanke) lagen quer ueber „Alle" und mitten im Text und
     sind wieder raus. Rein dekorativ: es darf keinen Klick abfangen, sonst
     waere die Ecke der Meldung tot. */
  .dv2-news-blatt {
    position: absolute; pointer-events: none; z-index: 2;
    width: 82px; bottom: -18px; left: -26px; transform: rotate(-6deg);
  }
  [data-theme="dark"] .dv2-news-blatt { filter: brightness(.72) saturate(.85); }

  .dv2-news-spalte {
    position: relative; z-index: 1; min-width: 0;
    display: grid; grid-template-rows: auto 1fr auto; gap: 8px;
  }
  /* Ohne Bild lief der Text ueber die volle Kastenbreite - rund 78 Zeichen je
     Zeile, deutlich ueber den 65-75, die sich noch gut lesen. Der Deckel haelt
     die Zeilen kurz und laesst rechts zugleich die Luft, die die Vorlage dort
     hat (dort steht in der Ecke das Bild). Mit Bild braucht es ihn nicht - da
     ist die Spalte ohnehin schmal. */
  .dv2-news:not(.hat-bild) .dv2-news-spalte { max-width: 76%; }

  /* Heller Schleier unter dem Text. In der Vorlage ist die linke Haelfte fast
     leer, weil das Bild rechts die Zeichnung verdeckt. Ohne Bild liegen Wolken
     und Kirchturm frei - gemessen kam die Kurzfassung dort auf 2,7:1, also
     unter den geforderten 4,5:1. Der Schleier laeuft nach rechts aus, damit er
     nicht als Kasten im Kasten wirkt. */
  .dv2-news-spalte::before {
    content: ''; position: absolute; z-index: -1;
    inset: -24px -56px -20px -12px;
    border-radius: 18px;
    /* Deckend bis hinter das letzte Wort, danach schnell aus. Links deckt er
       ohnehin nur Himmel zu - dort aendert sich fast nichts; rechts nimmt er
       Sonne, Mond und Kirchturm aus dem Text heraus. Schwaechere Fassungen
       (80 %) kamen im Dunkelmodus ueber dem Mond auf 1,2:1.
       Die 12px links sind der Auslauf zur Kastenkante hin (siehe unten).
       Bewusst in PIXELN, nicht in Prozent: der linke Ueberhang ist 12 px breit,
       ein Prozentwert haengt dagegen an der Laenge der Verlaufsachse (bei 100deg
       auch von der Hoehe) und rutschte mit Bild/ohne Bild unterschiedlich weit
       unter den Text. */
    background: linear-gradient(100deg,
      transparent 0,
      color-mix(in srgb, var(--card) 95%, transparent) 16px,
      color-mix(in srgb, var(--card) 95%, transparent) 78%,
      color-mix(in srgb, var(--card) 50%, transparent) 90%,
      transparent 100%);
    /* ⚠️ Die 95 % sind gemessen, nicht gegriffen. Im Textbereich des dunklen
       Hintergrundbilds liegt der hellste Punkt bei Helligkeit 0,86 - das ist der
       Mond. Bei 80 % Deckkraft faellt der Text dort auf 2,0:1.
       VERSUCH, DER NICHT FUNKTIONIERT HAT: mit backdrop-filter: blur(18px) sinkt
       der Mond rechnerisch auf 0,21, dann reichten 80 %. Der Filter malt an
       dieser Stelle aber gar nicht - der Schleier liegt mit z-index:-1 hinter
       dem Inhalt und hat keinen Backdrop zu filtern. Auch ohne den drop-shadow
       am Kasten aendert sich nichts. Wer es erneut versucht: erst pruefen, ob
       es wirklich malt, sonst verliert man nur Kontrast. */
    /* ⚠️ Oben, links und unten endete der Schleier vorher HART - gemessen genau
       4 px innerhalb der Kastenkante. Zwischen dem gezeichneten Rand des Kastens
       und dieser Kante blieb ein schmaler Streifen Zeichnung stehen, und die
       Kante lief als sichtbare Linie quer ueber das Hintergrundbild. In beiden
       Themes.
       Der Auslauf liegt bewusst NUR im Ueberhang: oben sind es 11 px bis zur
       Kopfzeile, unten 8 px bis zur Blaetterleiste, links 12 px. Bei voller
       Deckung ab genau diesen Werten faded nichts unter dem Text weg - die
       gemessenen Kontraste von oben bleiben unangetastet.
       ⚠️ Der Auslauf reicht jetzt bis in die erste Textzeile hinein (18 px statt
       11). Das geht nur, WEIL weichgezeichnet wird: der Text braucht die volle
       Deckkraft nicht mehr, um vom Hintergrund freizukommen. Ohne Weichzeichnung
       waere das ein Rueckschritt. */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 24px, #000 calc(100% - 20px), transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 24px, #000 calc(100% - 20px), transparent 100%);
  }

  .dv2-news-kopf { display: flex; align-items: center; gap: 10px; }
  /* Die Kopfzeile ist eine Beschriftung, nicht die Nachricht: kleiner als der
     Titel und etwas gesperrt. Vorher lagen beide fast gleichauf (.86 zu .93rem)
     und stritten um den ersten Blick. */
  .dv2-news-hdr {
    display: inline-flex; align-items: center; gap: 7px; min-width: 0;
    font-size: clamp(.72rem, .88cqw, .8rem); font-weight: 700; letter-spacing: .01em;
    color: var(--text2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .dv2-news-tute { font-size: 1.15em; line-height: 1; }
  .dv2-news-alle {
    margin-left: auto; flex: none;
    border: 0; background: none; cursor: pointer; padding: 2px 2px;
    font-family: inherit; font-size: clamp(.7rem, .85cqw, .78rem); font-weight: 700;
    color: var(--dv2-primary-text, var(--primary));
    white-space: nowrap;
  }
  .dv2-news-alle:hover { text-decoration: underline; }

  /* Die Meldung ist als Ganzes anklickbar - laut Vorgabe fuehrt auch sie in
     die Patchnotes. Deshalb ein <button>, kein <div> mit onclick: so
     erreicht man sie auch mit der Tastatur. */
  .dv2-news-eintrag {
    display: grid; gap: 4px; align-content: start; justify-items: start;
    margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
    font-family: inherit; text-align: left; color: inherit;
  }
  /* Beim Blaettern wird der Inhalt im selben Kasten ausgetauscht - ein kurzes
     Ueberblenden macht sichtbar, DASS gewechselt wurde. Nur transform und
     opacity, damit nichts neu umbricht. */
  @keyframes dv2-news-auf {
    from { opacity: 0; transform: translateY(5px); }
    to   { opacity: 1; transform: none; }
  }
  .dv2-news-eintrag.ist-gewechselt { animation: dv2-news-auf .2s ease-out; }
  @media (prefers-reduced-motion: reduce) {
    .dv2-news-eintrag.ist-gewechselt { animation: none; }
  }
  .dv2-news-titel {
    font-size: clamp(.88rem, 1.12cqw, 1.02rem); font-weight: 800; line-height: 1.28;
    color: var(--text); text-wrap: balance;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  /* Vier Zeilen sind der Deckel, und der Kasten waechst bis dahin mit.
     Gemessen: bei 1600px Fensterbreite passen die vollen 180 Zeichen in drei
     Zeilen, bei der schmalsten Buehne (seit 05.09. 1100px statt 1300) deutlich
     weniger - die vierte Zeile faengt genau diesen Fall ab. Was dann noch uebersteht, endet mit „…"; die
     vollstaendige Meldung steht einen Klick weiter in den Patchnotes. */
  /* Eine Spur kraeftiger als --text2: rein in --text2 lag die Kurzfassung
     gemessen bei 4,4:1, knapp unter den geforderten 4,5. Heller als der Titel
     bleibt sie trotzdem deutlich. */
  .dv2-news-text {
    font-size: clamp(.7rem, .86cqw, .78rem); font-weight: 500; line-height: 1.55;
    color: color-mix(in srgb, var(--text2) 82%, var(--text));
    display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
  }
  /* Zahlen tabellarisch: sonst springt „Heute, 12:04" bei jeder Minute in der
     Breite. Und in --text2 statt --text3 - auf der hellen Kastengrafik war die
     dritte Stufe zu blass. */
  .dv2-news-zeit {
    margin-top: 3px;
    font-size: clamp(.64rem, .76cqw, .7rem); font-weight: 600; color: var(--text2);
    font-variant-numeric: tabular-nums;
  }
  .dv2-news-eintrag:hover .dv2-news-titel { color: var(--dv2-primary-text, var(--primary)); }
  .dv2-news-leer {
    align-self: center;
    font-size: .76rem; font-weight: 600; color: var(--text3, var(--text2)); font-style: italic;
  }

  .dv2-news-pager {
    display: flex; align-items: center; justify-content: center; gap: 4px;
    margin-top: 2px;
  }
  .dv2-news-pfeil {
    width: 26px; height: 26px; padding: 0; border: 0; border-radius: 50%;
    background: none; cursor: pointer;
    display: grid; place-items: center;
    font-family: inherit; font-size: 1.15rem; line-height: 1;
    color: var(--text2);
    transition: background .15s, color .15s, transform .12s;
  }
  .dv2-news-pfeil:hover { background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text); }
  .dv2-news-pfeil:active { transform: scale(.9); }
  .dv2-news-punkte { display: flex; align-items: center; }
  /* Der Punkt ist 8px gross, die Schaltflaeche 22px: sonst muesste man auf
     acht Pixel genau treffen. Der sichtbare Punkt kommt deshalb aus ::after. */
  .dv2-news-punkt {
    width: 22px; height: 22px; padding: 0; border: 0; border-radius: 50%;
    background: none; cursor: pointer;
    display: grid; place-items: center;
  }
  .dv2-news-punkt::after {
    content: ''; width: 7px; height: 7px; border-radius: 50px;
    background: color-mix(in srgb, var(--text) 26%, transparent);
    transition: background .18s, width .18s, transform .15s;
  }
  .dv2-news-punkt:hover::after { transform: scale(1.25); }
  /* Die aktive Meldung ist ein Riegel statt eines Punktes. Nur ueber die Farbe
     zu gehen waere zu wenig - bei Farbenblindheit sieht man sonst nicht, wo man
     gerade steht. Form und Farbe zusammen. */
  .dv2-news-punkt.ist-da::after {
    width: 18px; background: var(--dv2-primary-text, var(--primary));
  }
  .dv2-news-punkt.ist-da:hover::after { transform: none; }

  /* Tastatur: sichtbarer Ring auf allem, was im Kasten anklickbar ist. Der
     fehlte - mit der Tabulatortaste war nicht zu erkennen, wo man steht. */
  .dv2-news-alle:focus-visible,
  .dv2-news-eintrag:focus-visible,
  .dv2-news-pfeil:focus-visible,
  .dv2-news-punkt:focus-visible,
  .dv2-kalenderlink:focus-visible {
    outline: 2px solid var(--dv2-primary-text, var(--primary));
    outline-offset: 3px; border-radius: 8px;
  }
  .dv2-news-punkt:focus-visible, .dv2-news-pfeil:focus-visible { border-radius: 50%; outline-offset: 1px; }

  /* Das Bild sitzt in der unteren rechten Ecke des Kastens. Die Ecken sind in
     der Vorlage schon abgerundet; der Radius hier faengt die Bilder ab, bei
     denen das nicht so ist. */
  .dv2-news-bild {
    position: relative; z-index: 1;
    width: 100%; height: 100%; min-height: 0;
    object-fit: cover; object-position: center;
    border-radius: 14px;
  }

  /* ── Verweis auf den Kalender ──────────────────────────────────────────
     Klein und leise: der Kalender ist ab jetzt ein Fenster, kein Dauergast
     auf der Buehne. */
  .dv2-kalenderlink {
    display: inline-flex; align-items: center; gap: 7px;
    margin: -2px 4px 0 0; padding: 5px 12px;
    border: 1px solid var(--border-weich, var(--border)); border-radius: 50px;
    background: color-mix(in srgb, var(--card) 76%, transparent);
    backdrop-filter: blur(7px); cursor: pointer;
    font-family: inherit; font-size: .74rem; font-weight: 700; color: var(--text2);
    box-shadow: 0 4px 12px rgba(28,44,74,.10);
  }
  .dv2-kalenderlink:hover { color: var(--text); border-color: var(--dv2-primary-text, var(--primary)); }
  .dv2-kalenderlink-ico { font-size: .95em; line-height: 1; }

  /* ── Chat nach dem Entwurf ─────────────────────────────────────────────
     Zwei Zustaende desselben Chats: klein (Verlauf + schmale Online-Leiste)
     und gross (Kanaele | Verlauf | Online). Der Wechsel haengt an
     .chat-modal-mode, die toggleChatModal() schon setzt.

     Die Nachrichten selbst kommen unveraendert aus chatAddMessage(); hier
     wird nur ihre Anordnung geaendert. Vorher standen Name, Text und Zeit
     UNTEREINANDER - drei Zeilen je Nachricht. Deshalb war bei kleiner
     Chathoehe kaum mehr als eine Nachricht zu sehen. */
  .ls-chat-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 104px;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "kopf    kopf"
      "verlauf leiste"
      "eingabe eingabe";
    gap: 0;
  }
  .ls-chat-body > .ls-chat-status { grid-area: kopf; }
  .ls-chat-body > #chatMessages   { grid-area: verlauf; min-height: 0; }
  .ls-chat-body > .dv2-chat-online { grid-area: leiste; }
  .ls-chat-body > .chat-input-row { grid-area: eingabe; }
  .ls-chat-body > .dv2-chat-kanaele { display: none; }

  /* Kopfzeile: Kanalname, Sprache, Vergroessern. */
  .ls-chat-body > .ls-chat-status {
    display: flex; align-items: center; gap: 8px;
    padding: 5px 10px; border-bottom: 1px solid var(--border-weich, var(--border));
  }
  .dv2-chat-kanalname {
    font-size: .78rem; font-weight: 800; color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .ls-chat-body .ls-chat-channels { margin-left: auto; }

  /* ── Nachrichten kompakt ──────────────────────────────────────────────
     Name, Abzeichen und Zeit teilen sich EINE Zeile, der Text steht darunter.
     Statt drei Zeilen also zwei - und die Zeit wandert nach rechts aussen,
     wo sie leise bleibt. */
  /* style.css setzt hier feste 260px. Im Raster soll der Verlauf die Zeile
     fuellen - klein wie gross. Ohne das blieb im Modal unter den Nachrichten
     ein leeres Drittel stehen. */
  .ls-chat-body #chatMessages { height: auto; min-height: 0; padding: 4px 2px; }
  .ls-chat-body .chat-bubble-row {
    align-items: flex-start; gap: 7px; padding: 1px 8px; margin-bottom: 2px;
  }
  .ls-chat-body .chat-bubble-avatar {
    width: 22px; height: 22px; font-size: .66rem; margin-top: 1px;
  }
  .ls-chat-body .chat-bubble-body {
    max-width: calc(100% - 30px); width: 100%;
    display: grid; align-items: baseline; gap: 0 8px;
  }
  /* Klein: alles auf EINER Zeile - Name, Stufe, Zeit, dann die Blase.
     So zeigt es Konzept 2 der Vorlage, und so passt am meisten Verlauf ins
     Fenster. */
  .ls-chat-body:not(.chat-modal-mode) .chat-bubble-body {
    grid-template-columns: auto auto minmax(0, 1fr);
    grid-template-areas: "wer zeit text";
    align-items: center;
  }
  /* Gross: zwei Zeilen wie Konzept 1 - dort ist Platz und die Blase darf
     ueber die volle Breite laufen. */
  .ls-chat-body.chat-modal-mode .chat-bubble-body {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "wer zeit" "text text";
  }
  .ls-chat-body .chat-bubble-meta { grid-area: wer; flex-wrap: nowrap; min-width: 0; }
  .ls-chat-body .chat-bubble-time {
    grid-area: zeit; font-size: .58rem; color: var(--text3);
    white-space: nowrap; padding: 0;
  }
  /* Klein steht die Zeit direkt hinter der Stufe (Vorlage), gross rechts
     aussen am Zeilenende. */
  .ls-chat-body.chat-modal-mode .chat-bubble-time { justify-self: end; }
  /* Rasterfelder werden von sich aus auf die volle Zeilenbreite gedehnt.
     Bei "<3" oder "+" sah die Blase dadurch aus wie ein leeres Eingabefeld.
     justify-self haelt sie auf Inhaltsbreite. */
  .ls-chat-body .chat-bubble {
    grid-area: text; justify-self: start; max-width: 100%; width: fit-content;
  }
  .ls-chat-body .chat-sticker { grid-area: text; justify-self: start; }
  /* Eigene Nachrichten: gleiche Hoehe, nur andere Farbe - der Entwurf will
     Hervorhebung ohne Mehrverbrauch. */
  .ls-chat-body .chat-bubble-row--me { flex-direction: row; }
  .ls-chat-body .chat-bubble-row--me .chat-bubble-body { align-items: baseline; }
  .ls-chat-body .chat-bubble-row--me .chat-bubble-meta { flex-direction: row; }
  /* Weich statt umrandet: die Vorlage zeigt Blasen OHNE Kontur, nur als
     leicht abgesetzte Flaeche. style.css setzt hier eine 1.5px-Linie auf
     weissem Grund - das wirkte hart wie ein Eingabefeld.
     --surface2 ist im Spiel genau dafuer da ("eine Spur abgesetzt"): hell
     etwas kuehler als Weiss, dunkel etwas tiefer als das Panel. */
  .ls-chat-body .chat-bubble,
  .ls-chat-body .chat-bubble--me {
    padding: 4px 10px; border-radius: 12px;
    border: 0; box-shadow: none;
    font-size: .74rem; line-height: 1.35;
  }
  .ls-chat-body .chat-bubble {
    background: var(--surface2); color: var(--text);
  }
  /* Eigene Nachrichten nur leicht anders eingefaerbt - gleicher Platzbedarf,
     kein zweiter Rahmen, keine Sonderschriftfarbe. */
  .ls-chat-body .chat-bubble--me {
    background: var(--primary-l, #eef2ff); color: var(--text);
  }
  .ls-chat-body .chat-bubble--me strong,
  .ls-chat-body .chat-bubble--me em { color: inherit; }
  .ls-chat-body .chat-bubble-name { font-size: .68rem; }
  .ls-chat-body .chat-lvl { font-size: .58rem; }
  .ls-chat-body .chat-action-row { padding: 1px 10px; margin-bottom: 2px; }

  /* Sticker begrenzen - sonst fuellt ein einziges Emote den Ausschnitt. */
  /* Deutlich kleiner als zuvor: mit 72px sprengte ein einziger Sticker die
     Zeile und schob den Verlauf zusammen. 48px bleibt klar groesser als Text,
     ohne den Ausschnitt zu beherrschen. */
  .ls-chat-body .chat-sticker { width: auto; height: auto; max-height: 48px; max-width: 64px; }
  .ls-chat-body.chat-modal-mode .chat-sticker { max-height: 96px; max-width: 130px; }

  /* ── Online-Leiste ────────────────────────────────────────────────────
     Klein: nur Buchstabenkreise in zwei Spalten. Gross: Kreis + Name.
     Level und Ort fehlen bewusst - GET:online liefert sie nicht. */
  .dv2-chat-online {
    border-left: 1px solid var(--border-weich, var(--border));
    padding: 6px 5px; overflow-y: auto; scrollbar-width: thin;
  }
  .dv2-chat-online-kopf {
    display: flex; align-items: center; gap: 5px; margin-bottom: 6px;
    font-size: .62rem; font-weight: 800; color: var(--text2);
  }
  .dv2-chat-punkt { width: 6px; height: 6px; border-radius: 50%; background: #22c55e; flex: none; }
  .dv2-chat-online-liste { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
  /* "+17" wie in der Vorlage, wenn mehr da sind als die Leiste zeigt. */
  .dv2-chat-mehr {
    grid-column: 1 / -1; justify-self: start;
    display: inline-flex; align-items: center; height: 22px; padding: 0 9px;
    border-radius: 50px; font-size: .66rem; font-weight: 800;
    color: var(--dv2-primary-text); background: var(--primary-l, rgba(79,110,247,.14));
  }
  .dv2-chat-online-eintrag {
    display: flex; align-items: center; gap: 6px; min-width: 0;
    padding: 2px; border: 0; border-radius: 8px; background: none;
    cursor: pointer; transition: background .14s;
  }
  .dv2-chat-online-eintrag:disabled { cursor: default; }
  .dv2-chat-online-eintrag:hover:not(:disabled) { background: var(--bg2, rgba(0,0,0,.05)); }
  .dv2-chat-online-bild {
    flex: none; display: grid; place-items: center;
    width: 26px; height: 26px; border-radius: 50%;
    font-size: .66rem; font-weight: 800;
    color: #fff; background: var(--primary);
  }
  .dv2-chat-online-eintrag.ist-ich .dv2-chat-online-bild { background: #7c3aed; }
  /* Klein: der Name traegt nichts bei, es fehlt die Breite. Er bleibt als
     title am Knopf und ist damit beim Zeigen lesbar. */
  .dv2-chat-online-name { display: none; }

  /* ── Grosse Ansicht ───────────────────────────────────────────────────
     Kanaele links, Verlauf in der Mitte, Online rechts. */
  /* style.css setzt hier "display:flex!important" an einer ID - fuer das
     Raster muss beides gleichziehen. Dasselbe gilt fuer die dort fest
     gesetzte Stickergroesse. */
  #lsChatPane.chat-modal-mode { display: grid !important; }

  /* Groesser als die 700x620 aus style.css - der Verlauf ist der Grund, warum
     man ueberhaupt vergroessert. Zusaetzlich am rechten unteren Eck ziehbar:
     resize braucht ein overflow ausser 'visible', deshalb hidden dazu.
     Die Grenzen halten das Fenster brauchbar: unter 520x380 zerfaellt das
     Dreispaltenraster, ueber 96vw/92vh klebt es am Bildschirmrand.
     Weil das Fenster ueber transform mittig sitzt, waechst es beim Ziehen
     nach allen Seiten - es bleibt also zentriert. */
  #lsChatPane.chat-modal-mode {
    width: min(1080px, 92vw); height: min(760px, 88vh);
    min-width: 520px; min-height: 380px;
    max-width: 96vw; max-height: 92vh;
    resize: both; overflow: hidden;
  }
  #lsChatPane.chat-modal-mode .chat-sticker {
    width: auto !important; height: auto !important;
    max-height: 96px; max-width: 130px;
  }
  .ls-chat-body.chat-modal-mode {
    grid-template-columns: 172px minmax(0, 1fr) 196px;
    grid-template-areas:
      "kopf    kopf    kopf"
      "kanaele verlauf leiste"
      "kanaele eingabe leiste";
  }
  .ls-chat-body.chat-modal-mode > .dv2-chat-kanaele {
    display: block; grid-area: kanaele;
    border-right: 1px solid var(--border-weich, var(--border));
    padding: 9px 8px; overflow-y: auto; scrollbar-width: thin;
  }
  .dv2-chat-spaltentitel {
    margin: 0 0 7px; padding: 0 6px;
    font-size: .64rem; font-weight: 800; letter-spacing: .05em;
    text-transform: uppercase; color: var(--text2);
  }
  .dv2-chat-kanal {
    display: flex; align-items: center; gap: 7px; width: 100%;
    min-height: 34px; padding: 0 9px; margin-bottom: 2px;
    border: 0; border-radius: 9px; background: none; cursor: pointer;
    font-size: .8rem; font-weight: 700; color: var(--text2); text-align: left;
    transition: background .14s, color .14s;
  }
  .dv2-chat-kanal:hover { background: var(--bg2, rgba(0,0,0,.05)); color: var(--text); }
  .dv2-chat-kanal.ist-aktiv {
    background: var(--primary-l, rgba(79,110,247,.12)); color: var(--dv2-primary-text);
  }
  .dv2-chat-raute { font-weight: 800; opacity: .6; }
  /* Gross ist Platz fuer den Namen neben dem Kreis. */
  .ls-chat-body.chat-modal-mode .dv2-chat-online-liste { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .ls-chat-body.chat-modal-mode .dv2-chat-online-name {
    display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font-size: .76rem; font-weight: 700; color: var(--text);
  }
  .ls-chat-body.chat-modal-mode .dv2-chat-online-eintrag { padding: 3px 5px; }
  .ls-chat-body.chat-modal-mode .dv2-chat-online-kopf { font-size: .68rem; }
  .ls-chat-body.chat-modal-mode .dv2-chat-online { padding: 9px 8px; }

  /* Wird es zu eng, weicht zuerst die Kanalspalte, dann der Name in der
     Online-Leiste. Der Verlauf behaelt immer Vorrang. */
  @media (max-width: 1180px) {
    .ls-chat-body.chat-modal-mode {
      grid-template-columns: minmax(0, 1fr) 104px;
      grid-template-areas:
        "kopf    kopf"
        "verlauf leiste"
        "eingabe leiste";
    }
    .ls-chat-body.chat-modal-mode > .dv2-chat-kanaele { display: none; }
    .ls-chat-body.chat-modal-mode .dv2-chat-online-liste { grid-template-columns: repeat(2, 1fr); }
    .ls-chat-body.chat-modal-mode .dv2-chat-online-name { display: none; }
  }

  /* ── Emote-Auswahl als Popover ueber dem Eingabefeld ──────────────────
     Vorher lag sie im Fluss zwischen Nachrichten und Eingabe und schob den
     Verlauf zusammen. Jetzt schwebt sie ueber der Eingabezeile und laesst
     die Nachrichten in Ruhe. */
  .ls-chat-body #chatEmotePicker {
    position: absolute; right: 8px; bottom: 46px; z-index: 30;
    width: min(320px, calc(100% - 16px));
    border: 1px solid var(--border); border-radius: 14px;
    box-shadow: 0 10px 30px rgba(28, 44, 74, .22);
    background: var(--card);
  }
  .ls-chat-body { position: relative; }
  .ls-chat-body.chat-modal-mode #chatEmotePicker { width: min(380px, 60%); }

  @media (max-width: 1100px) {
    .dv2-navbtn-lbl { display: none; }
    .dv2-navbtn { padding: 0 10px; }
    .dv2-mega-liste { grid-template-columns: minmax(0, 1fr); }
  }

  /* ── Schnellzugriff (Seitenleiste) ─────────────────────────────────────────
     Raster und Kachel sind die des Begleiter-Teams (.sb-comp-grid, .sb-comp-tile) —
     hier steht nur, was dazukommt: Symbol, Name darunter, Hinweismarke. */
  .dv2-sc { padding: 7px 10px 9px; border-bottom: 1.5px solid var(--border); flex-shrink: 0; }
  .dv2-sc[hidden] { display: none; }
  .dv2-sc-raster { margin-top: 5px; }
  .dv2-sc-kachel {
    all: unset; box-sizing: border-box; min-width: 0; cursor: pointer;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
  }
  .dv2-sc-kachel:focus-visible .dv2-sc-feld { outline: 2px solid var(--primary); outline-offset: 2px; }
  .dv2-sc-feld { width: 100%; color: var(--dv2-primary-text); }
  .dv2-sc-kachel:hover .dv2-sc-feld { border-color: var(--primary); transform: translateY(-2px); }
  .dv2-sc-feld .dv2-ico { width: 44%; height: 44%; }
  /* Beschriftung: bei 1100 px hat die Zelle nur 51 px. Einzeilig mit Auslassung schnitt
     Englisch 5 von 18 Namen ab; zweizeilig mit break-word trennte ohne Silbentrennungs-
     woerterbuch hart „Fähigkeite|n". Darum: 0,58 rem, leicht enger, und 3 px in jeden
     Zwischenraum hinein (57 px) — dann passt jedes einzelne Wort, auch „Expeditionen"
     (56 px). Zwei Zeilen nur ZWISCHEN Woertern („Battle / Pass"), nie mitten im Wort.
     hyphens:auto bleibt als Netz fuer Browser, die trennen koennen. */
  .dv2-sc-raster { align-items: start; }
  .dv2-sc-name {
    width: calc(100% + 6px); margin: 0 -3px;
    font-size: .58rem; font-weight: 700; line-height: 1.15; letter-spacing: -.01em;
    color: var(--text2); text-align: center; overflow-wrap: normal;
    hyphens: auto; -webkit-hyphens: auto;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  }
  /* Rot wie die uebrigen Hinweise im Menue. */
  .dv2-sc-marke {
    position: absolute; top: 3px; right: 3px; min-width: 15px; height: 15px; padding: 0 4px;
    display: grid; place-items: center; border-radius: 50px;
    font-size: .6rem; font-weight: 900; color: #fff; background: var(--red);
    box-shadow: 0 0 0 2px var(--card);
  }
  .dv2-sc-marke[hidden] { display: none; }

  /* Auswahl im Profilmenue (genericModal) */
  .dv2-sc-wahl { display: flex; flex-direction: column; gap: 10px; }
  .dv2-sc-hinweis { margin: 0; font-size: .82rem; line-height: 1.45; color: var(--text2); }
  .dv2-sc-zaehler { font-size: .76rem; font-weight: 800; color: var(--dv2-primary-text); }
  .dv2-sc-gruppe h4 {
    margin: 0 0 6px; font-size: .66rem; font-weight: 900; letter-spacing: .08em;
    text-transform: uppercase; color: var(--text2);
  }
  .dv2-sc-optionen { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 5px; }
  .dv2-sc-option {
    position: relative; font: inherit; cursor: pointer;
    display: flex; flex-direction: column; align-items: center; gap: 5px;
    padding: 7px 5px 6px; border-radius: 10px;
    background: var(--surface2); border: 1.5px solid var(--border); color: var(--text);
  }
  .dv2-sc-option:hover:not(:disabled) { border-color: var(--primary); }
  .dv2-sc-option.ist-an { border-color: var(--primary); background: var(--primary-l); }
  .dv2-sc-option:disabled { opacity: .42; cursor: not-allowed; }
  .dv2-sc-option-icon { color: var(--dv2-primary-text); }
  .dv2-sc-option-icon .dv2-ico { width: 20px; height: 20px; }
  .dv2-sc-option-name { font-size: .72rem; font-weight: 700; text-align: center; line-height: 1.2; }
  .dv2-sc-option-pos {
    position: absolute; top: 4px; right: 5px; min-width: 17px; height: 17px;
    display: grid; place-items: center; border-radius: 50px;
    font-size: .62rem; font-weight: 900; color: #fff; background: var(--primary);
  }
  /* Knopfleiste klebt unten: bei 18 Zielen laeuft der Dialog auf kleineren Fenstern
     ueber, und Speichern darf nie erst nach dem Scrollen auftauchen. */
  .dv2-sc-knoepfe {
    position: sticky; bottom: 0; z-index: 1;
    display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px;
    margin-top: 2px; padding: 10px 0 2px; background: var(--card);
    border-top: 1.5px solid var(--border);
  }


  /* ── Tastenkuerzel-Einstellungen (genericModal) ───────────────────────── */
  .tk-wahl { display: flex; flex-direction: column; gap: 10px; }
  .tk-schalter { display: flex; align-items: center; gap: 8px; font-size: .9rem; cursor: pointer; }
  .tk-schalter input { width: 18px; height: 18px; accent-color: var(--primary); }
  .tk-hinweis { margin: 0; font-size: .78rem; line-height: 1.45; color: var(--text2); }
  .tk-liste { display: flex; flex-direction: column; gap: 12px; transition: opacity .15s; }
  /* Aus: sichtbar und aenderbar, aber erkennbar ohne Wirkung. */
  .tk-liste.ist-aus { opacity: .55; }
  .tk-gruppe h4 {
    margin: 0 0 4px; font-size: .66rem; font-weight: 900; letter-spacing: .08em;
    text-transform: uppercase; color: var(--text2);
  }
  .tk-zeile {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 5px 8px; border-radius: 8px;
  }
  .tk-zeile:nth-child(even) { background: var(--surface2); }
  .tk-zeile.ist-doppelt { box-shadow: inset 3px 0 0 var(--red); }
  .tk-name { font-size: .82rem; font-weight: 600; color: var(--text); min-width: 0; }
  .tk-taste {
    flex: none; min-width: 44px; height: 30px; padding: 0 10px; cursor: pointer;
    font: 800 .78rem/1 var(--font-ui, system-ui, sans-serif); color: var(--text);
    background: var(--card); border: 1.5px solid var(--border); border-radius: 7px;
    box-shadow: 0 2px 0 var(--border);
  }
  .tk-taste:hover { border-color: var(--primary); }
  .tk-taste.ist-frei { color: var(--text2); font-weight: 600; }
  .tk-taste.wartet { border-color: var(--primary); background: var(--primary-l); color: var(--dv2-primary-text); min-width: 120px; }
  .tk-meldung { min-height: 1.1em; font-size: .78rem; font-weight: 700; color: var(--dv2-primary-text); }
  .tk-meldung:empty { display: none; }
}
